Spring框架系列(11)(spring框架基础知识)

  本篇文章为你整理了Spring框架系列(11)(spring框架基础知识)的详细内容,包含有spring框架总结 spring框架基础知识 spring框架视频讲解 spring框架入门教程 Spring框架系列(11),希望能帮助你了解 Spring框架系列(11)。

  我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。@pdai

  
我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。

  要了解动态代理是如何工作的,首先需要了解

  什么是代理模式?

  什么是动态代理?

  什么是Cglib?

  SpringAOP和Cglib是什么关系?

  动态代理要解决什么问题?

  什么是代理?

  代理模式(Proxy pattern): 为另一个对象提供一个替身或占位符以控制对这个对象的访问

  举个简单的例子:

  我(client)如果要买(doOperation)房,可以找中介(proxy)买房,中介直接和卖方(target)买房。中介和卖方都实现买卖(doOperation)的操作。中介就是代理(proxy)。

  什么是动态代理?

  动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。

  在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。

  什么是Cglib? SpringAOP和Cglib是什么关系?

  Cglib是一个强大的、高性能的代码生成包,它广泛被许多AOP框架使用,为他们提供方法的拦截。

  最顶层是字节码,字节码相关的知识请参考 JVM基础 - 类字节码详解

  ASM是操作字节码的工具

  cglib基于ASM字节码工具操作字节码(即动态生成代理,对方法进行增强)

  SpringAOP基于cglib进行封装,实现cglib方式的动态代理

  Cglib代理的案例

  这里我们写一个使用cglib的简单例子。@pdai

  pom包依赖

  引入cglib的依赖包

  

 ?xml version="1.0" encoding="UTF-8"? 

 

   project xmlns="http://maven.apache.org/POM/4.0.0"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

   parent

   artifactId tech-pdai-spring-demos /artifactId

   groupId tech.pdai /groupId

   version 1.0-SNAPSHOT /version

   /parent

   modelVersion 4.0.0 /modelVersion

   artifactId 007-spring-framework-demo-aop-proxy-cglib /artifactId

   properties

   maven.compiler.source 8 /maven.compiler.source

   maven.compiler.target 8 /maven.compiler.target

   /properties

   dependencies

   !-- https://mvnrepository.com/artifact/cglib/cglib --

   dependency

   groupId cglib /groupId

   artifactId cglib /artifactId

   version 3.3.0 /version

   /dependency

   /dependencies

   /project

  

 

  User

  

package tech.pdai.springframework.entity;

 

   * @author pdai

  public class User {

   * users name.

   private String name;

   * users age.

   private int age;

   * init.

   * @param name name

   * @param age age

   public User(String name, int age) {

   this.name = name;

   this.age = age;

   public String getName() {

   return name;

   public void setName(String name) {

   this.name = name;

   public int getAge() {

   return age;

   public void setAge(int age) {

   this.age = age;

   @Override

   public String toString() {

   return "User{" +

   "name=" + name + \ +

   ", age=" + age +

   };

  

 

  被代理的类

  即目标类, 对被代理的类中的方法进行增强

  

package tech.pdai.springframework.service;

 

  import java.util.Collections;

  import java.util.List;

  import tech.pdai.springframework.entity.User;

   * @author pdai

  public class UserServiceImpl {

   * find user list.

   * @return user list

   public List User findUserList() {

   return Collections.singletonList(new User("pdai", 18));

   * add user

   public void addUser() {

   // do something

  

 

  cglib代理

  cglib代理类,需要实现MethodInterceptor接口,并指定代理目标类target

  

package tech.pdai.springframework.proxy;

 

  import java.lang.reflect.Method;

  import net.sf.cglib.proxy.Enhancer;

  import net.sf.cglib.proxy.MethodInterceptor;

  import net.sf.cglib.proxy.MethodProxy;

   * This class is for proxy demo.

   * @author pdai

  public class UserLogProxy implements MethodInterceptor {

   * 业务类对象,供代理方法中进行真正的业务方法调用

   private Object target;

   public Object getUserLogProxy(Object target) {

   //给业务对象赋值

   this.target = target;

   //创建加强器,用来创建动态代理类

   Enhancer enhancer = new Enhancer();

   //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)

   enhancer.setSuperclass(this.target.getClass());

   //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦

   enhancer.setCallback(this);

   // 创建动态代理类对象并返回

   return enhancer.create();

   // 实现回调方法

   @Override

   public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

   // log - before method

   System.out.println("[before] execute method: " + method.getName());

   // call method

   Object result = proxy.invokeSuper(obj, args);

   // log - after method

   System.out.println("[after] execute method: " + method.getName() + ", return value: " + result);

   return null;

  

 

  启动类中指定代理目标并执行。

  

package tech.pdai.springframework;

 

  import tech.pdai.springframework.proxy.UserLogProxy;

  import tech.pdai.springframework.service.UserServiceImpl;

   * Cglib proxy demo.

   * @author pdai

  public class ProxyDemo {

   * main interface.

   * @param args args

   public static void main(String[] args) {

   // proxy

   UserServiceImpl userService = (UserServiceImpl) new UserLogProxy().getUserLogProxy(new UserServiceImpl());

   // call methods

   userService.findUserList();

   userService.addUser();

  

 

  我们启动上述类main 函数,执行的结果如下:

  

[before] execute method: findUserList

 

  [after] execute method: findUserList, return value: [User{name=pdai, age=18}]

  [before] execute method: addUser

  [after] execute method: addUser, return value: null

  

 

  Cglib代理的流程

  我们把上述Demo的主要流程画出来,你便能很快理解

  更多细节:

  在上图中,我们可以通过在Enhancer中配置更多的参数来控制代理的行为,比如如果只希望增强这个类中的一个方法(而不是所有方法),那就增加callbackFilter来对目标类中方法进行过滤;Enhancer可以有更多的参数类配置其行为,不过我们在学习上述主要的流程就够了。

  final方法为什么不能被代理?很显然final方法没法被子类覆盖,当然不能代理了。

  Mockito为什么不能mock静态方法?因为mockito也是基于cglib动态代理来实现的,static方法也不能被子类覆盖,所以显然不能mock。但PowerMock可以mock静态方法,因为它直接在bytecode上工作,更多可以看Mockito单元测试。(pdai: 通了没?是不是so easy...)

  SpringAOP中Cglib代理的实现

  SpringAOP封装了cglib,通过其进行动态代理的创建。

  我们看下CglibAopProxy的getProxy方法

  

@Override

 

  public Object getProxy() {

   return getProxy(null);

  @Override

  public Object getProxy(@Nullable ClassLoader classLoader) {

   if (logger.isTraceEnabled()) {

   logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());

   try {

   Class ? rootClass = this.advised.getTargetClass();

   Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

   // 上面流程图中的目标类

   Class ? proxySuperClass = rootClass;

   if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {

   proxySuperClass = rootClass.getSuperclass();

   Class ? [] additionalInterfaces = rootClass.getInterfaces();

   for (Class ? additionalInterface : additionalInterfaces) {

   this.advised.addInterface(additionalInterface);

   // Validate the class, writing log messages as necessary.

   validateClassIfNecessary(proxySuperClass, classLoader);

   // 重点看这里,就是上图的enhancer,设置各种参数来构建

   Enhancer enhancer = createEnhancer();

   if (classLoader != null) {

   enhancer.setClassLoader(classLoader);

   if (classLoader instanceof SmartClassLoader

   ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {

   enhancer.setUseCache(false);

   enhancer.setSuperclass(proxySuperClass);

   enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));

   enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);

   enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));

   // 设置callback回调接口,即方法的增强点

   Callback[] callbacks = getCallbacks(rootClass);

   Class ? [] types = new Class ? [callbacks.length];

   for (int x = 0; x types.length; x++) {

   types[x] = callbacks[x].getClass();

   // 上节说到的filter

   enhancer.setCallbackFilter(new ProxyCallbackFilter(

   this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));

   enhancer.setCallbackTypes(types);

   // 重点:创建proxy和其实例

   return createProxyClassAndInstance(enhancer, callbacks);

   catch (CodeGenerationException IllegalArgumentException ex) {

   throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +

   ": Common causes of this problem include using a final class or a non-visible class",

   ex);

   catch (Throwable ex) {

   // TargetSource.getTarget() failed

   throw new AopConfigException("Unexpected AOP exception", ex);

  

 

  获取callback的方法如下,提几个理解的要点吧,具体读者在学习的时候建议把我的例子跑一下,然后打一个断点进行理解。

  rootClass: 即目标代理类

  advised: 包含上文中我们获取到的advisor增强器的集合

  exposeProxy: 在xml配置文件中配置的,背景就是如果在事务A中使用了代理,事务A调用了目标类的的方法a,在方法a中又调用目标类的方法b,方法a,b同时都是要被增强的方法,如果不配置exposeProxy属性,方法b的增强将会失效,如果配置exposeProxy,方法b在方法a的执行中也会被增强了

  DynamicAdvisedInterceptor: 拦截器将advised(包含上文中我们获取到的advisor增强器)构建配置的AOP的callback(第一个callback)

  targetInterceptor: xml配置的optimize属性使用的(第二个callback)

  最后连同其它5个默认的Interceptor 返回作为cglib的拦截器链,之后通过CallbackFilter的accpet方法返回的索引从这个集合中返回对应的拦截增强器执行增强操作。

  

private Callback[] getCallbacks(Class ? rootClass) throws Exception {

 

   // Parameters used for optimization choices...

   boolean exposeProxy = this.advised.isExposeProxy();

   boolean isFrozen = this.advised.isFrozen();

   boolean isStatic = this.advised.getTargetSource().isStatic();

   // Choose an "aop" interceptor (used for AOP calls).

   Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

   // Choose a "straight to target" interceptor. (used for calls that are

   // unadvised but can return this). May be required to expose the proxy.

   Callback targetInterceptor;

   if (exposeProxy) {

   targetInterceptor = (isStatic ?

   new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :

   new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));

   else {

   targetInterceptor = (isStatic ?

   new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :

   new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));

   // Choose a "direct to target" dispatcher (used for

   // unadvised calls to static targets that cannot return this).

   Callback targetDispatcher = (isStatic ?

   new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

   Callback[] mainCallbacks = new Callback[] {

   aopInterceptor, //

   targetInterceptor, // invoke target without considering advice, if optimized

   new SerializableNoOp(), // no override for methods mapped to this

   targetDispatcher, this.advisedDispatcher,

   new EqualsInterceptor(this.advised),

   new HashCodeInterceptor(this.advised)

   Callback[] callbacks;

   // If the target is a static one and the advice chain is frozen,

   // then we can make some optimizations by sending the AOP calls

   // direct to the target using the fixed chain for that method.

   if (isStatic isFrozen) {

   Method[] methods = rootClass.getMethods();

   Callback[] fixedCallbacks = new Callback[methods.length];

   this.fixedInterceptorMap = CollectionUtils.newHashMap(methods.length);

   // TODO: small memory optimization here (can skip creation for methods with no advice)

   for (int x = 0; x methods.length; x++) {

   Method method = methods[x];

   List Object chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);

   fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(

   chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());

   this.fixedInterceptorMap.put(method, x);

   // Now copy both the callbacks from mainCallbacks

   // and fixedCallbacks into the callbacks array.

   callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];

   System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);

   System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);

   this.fixedInterceptorOffset = mainCallbacks.length;

   else {

   callbacks = mainCallbacks;

   return callbacks;

  

 

  可以结合调试,方便理解

  https://github.com/realpdai/tech-pdai-spring-demos

  首先, 从Spring框架的整体架构和组成对整体框架有个认知。

  
Spring基础 - Spring和Spring框架组成

  Spring是什么?它是怎么诞生的?有哪些主要的组件和核心功能呢? 本文通过这几个问题帮助你构筑Spring和Spring Framework的整体认知。

  
Spring基础 - Spring简单例子引入Spring的核心

  上文中我们简单介绍了Spring和Spring Framework的组件,那么这些Spring Framework组件是如何配合工作的呢?本文主要承接上文,向你展示Spring Framework组件的典型应用场景和基于这个场景设计出的简单案例,并以此引出Spring的核心要点,比如IOC和AOP等;在此基础上还引入了不同的配置方式, 如XML,Java配置和注解方式的差异。

  
Spring基础 - SpringMVC请求流程和案例

  前文我们介绍了Spring框架和Spring框架中最为重要的两个技术点(IOC和AOP),那我们如何更好的构建上层的应用呢(比如web 应用),这便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技术基础上,遵循上述Web MVC的规范推出的web开发框架,目的是为了简化Java栈的web开发。 本文主要介绍SpringMVC的请求流程和基础案例的编写和运行。

  
Spring进阶 - Spring IOC实现原理详解之IOC体系结构设计

  在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解。本文将帮助你站在设计者的角度去看IOC最顶层的结构设计

  
Spring进阶 - Spring IOC实现原理详解之IOC初始化流程

  上文,我们看了IOC设计要点和设计结构;紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的

  
Spring进阶 - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

  上文,我们看了IOC设计要点和设计结构;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中存放的是Bean的定义即BeanDefinition放到beanDefinitionMap中,本质上是一个ConcurrentHashMap String, Object ;并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等。那么如何从BeanDefinition中实例化Bean对象呢,这是本文主要研究的内容?

  
Spring进阶 - Spring AOP实现原理详解之切面实现

  前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。

  
Spring进阶 - Spring AOP实现原理详解之AOP代理

  上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上继续介绍,代理(cglib代理和JDK代理)的实现过程。

  
Spring进阶 - Spring AOP实现原理详解之Cglib代理实现

  我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。

  
Spring进阶 - Spring AOP实现原理详解之JDK代理实现

  上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分。

  
Spring进阶 - SpringMVC实现原理之DispatcherServlet初始化的过程

  前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第一篇:DispatcherServlet的初始化过程的源码解析。

  
Spring进阶 - SpringMVC实现原理之DispatcherServlet处理请求的过程

  前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。

  以上就是Spring框架系列(11)(spring框架基础知识)的详细内容,想要了解更多 Spring框架系列(11)的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: