• 05Spring之AOP


    Spring之AOP

    动态代理

    代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。

    比如,现在存在一个类:

    public class UserServiceCGlib  {
    
        public void test() {
            System.out.println("test...");
        }
    
        public void a() {
            System.out.println("a...");
        }
    
    }
    

    如果我们现在想在不修改类的源码前提下,给test()增加额外逻辑,

    那么就可以使用动态代理机制来创建对象了

    CGlib

    public class TestCGlib {
    
        public static void main(String[] args) {
            //目标对象/被代理对象
            UserServiceCGlib target = new UserServiceCGlib();
    
            // 通过cglib技术
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(UserServiceCGlib.class);
    
            // 定义额外逻辑,也就是代理逻辑,所有方法都会执行代理逻辑
            enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
                //o 代理对象
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("before...");
                    //写法1,利用反射
                    //Object result =  method.invoke(target,objects);
                    //写法2,利用methodProxy
                    Object result = methodProxy.invoke(target, objects);
                    //错误写法 java.lang.StackOverflowError
                    //Object result = methodProxy.invoke(o, objects);
                    //写法3 执行代理类的父类
                    //Object result = methodProxy.invokeSuper(o, objects);
                    System.out.println("after...");
                    return result;
                }
            }});
    
            // 定义额外逻辑2,也就是代理逻辑,添加方法过滤
            enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
                        //o 代理对象
                        @Override
                        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                            System.out.println("before...");
                            //写法1,利用反射
                            //Object result =  method.invoke(target,objects);
                            //写法2,利用methodProxy
                            Object result = methodProxy.invoke(target, objects);
                            //错误写法 java.lang.StackOverflowError
                            //Object result = methodProxy.invoke(o, objects);
                            //写法3 执行代理类的父类
                            //Object result = methodProxy.invokeSuper(o, objects);
                            System.out.println("after...");
                            return result;
                        }
                    }, NoOp.INSTANCE}
            );
            enhancer.setCallbackFilter(new CallbackFilter() {
                @Override
                public int accept(Method method) {
                    if ("test".equals(method.getName())){
                        return 0;
                    }else{
                        return 1;
                    }
                }
            });
    
            // 动态代理所创建出来的对象也是UserService类型
            UserServiceCGlib userService = (UserServiceCGlib) enhancer.create();
    
            // 执行这个userService的test方法时,就会额外会执行一些其他逻辑
            userService.test();
            // 执行这个userService的a方法时,不会代理
            userService.a();
        }
    
    }
    

    结果如下

    before...
    test...
    after...
    a...
    

    上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的,对于程序员来说不用关心。

    Jdk

    除开cglib技术,jdk本身也提供了一种创建代理对象的动态代理机制,但是它只能代理接口,也就是UserService得先有一个接口才能利用jdk动态代理机制来生成一个代理对象,比如:

    public interface UserInterface {
        public void test();
    }
    
    

    利用JDK动态代理来生成一个代理对象:

    /**
     * 产生的代理对象的类型是UserInterface,而不是UserService
     */
    public class TestJdk {
    
        public static void main(String[] args) {
    
            //被代理对象
            UserInterface target = new UserInterface() {
                @Override
                public void test() {
                    System.out.println("test");
                }
            };
    
            // UserInterface接口的代理对象
            Object proxy = Proxy.newProxyInstance(TestJdk.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
                //proxy代理对象
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("before...");
                    Object result = method.invoke(target, args);
                    System.out.println("after...");
                    return result;
                }
            });
    
            UserInterface userInterface = (UserInterface) proxy;
            userInterface.test();
    
    
        }
    
    }
    

    结果如下

    before...
    test
    after...
    

    ProxyFactory

    上面我们介绍了两种动态代理技术,那么在Spring中进行了封装,封装出来的类叫做ProxyFactory,表示是创建代理对象的一个工厂,使用起来会比上面的更加方便,

    接口:

    public interface PeopleInterface {
        public void sayHello();
        
    }
    

    public class MyTarget {
        public void printName() {
            System.err.println("name:Target-");
        }
    }
    

    代理

    public class ProxyFactoryTest {
    
        public static void main(String[] args) {
            //使用JDK proxy生成代理类
            interfaceProxy();
            System.out.println("--------------");
            //使用CGlib生成代理类
            classProxy();
    
        }
    
        private static void interfaceProxy() {
            //代理对象指定接口PeopleService,目标类为实现PeopleService的EnglishService,使用JDK proxy生成代理类
            ProxyFactory factory = new ProxyFactory();
            factory.setInterfaces(new Class[] { PeopleInterface.class });
            factory.addAdvice(new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.err.println(invocation.getMethod().getName() + "调用之前");
                    Object res = invocation.proceed();//代理对象
                    System.err.println(invocation.getMethod().getName() + "调用之后");
                    return res;
                }
            });
            factory.setTarget(new PeopleInterface() {
                @Override
                public void sayHello() {
                    System.err.println("Hi~");
                }
    
            });
            PeopleInterface peopleProxy = (PeopleInterface) factory.getProxy();
            peopleProxy.sayHello();
            System.err.println(peopleProxy.getClass().getName());
        }
    
        public static void classProxy(){
            //代理对象未指定接口,使用CGLIB生成代理类
            ProxyFactory factory = new ProxyFactory();
            factory.setTarget(new MyTarget());
            factory.addAdvice(new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    System.err.println(invocation.getMethod().getName() + "调用之前");
                    Object res = invocation.proceed();
                    System.err.println(invocation.getMethod().getName() + "调用之后");
                    return res;
                }
            });
            MyTarget targetProxy = (MyTarget) factory.getProxy();
            targetProxy.printName();
            System.err.println(targetProxy.getClass().getName());
        }
        
    }
    

    结果

    sayHello调用之前
    Hi~
    sayHello调用之后
    com.sun.proxy.$Proxy0
    --------------
    printName调用之前
    name:Target-
    printName调用之后
    com.yoocar.spring.aop.proxyfactory.MyTarget$$EnhancerBySpringCGLIB$$7d50c3
    

    通过ProxyFactory,我们可以不再关系到底是用cglib还是jdk动态代理了,ProxyFactory会帮我们去判断,如果实现了接口,那么ProxyFactory底层就会用jdk动态代理,如果没有实现接口,就会用cglib技术

    Advice的分类

    Sring AOP通过Advice来指定在切点上具体做什么事情。如方法前做什么,方法后做什么,抛出异常做什么。

    1. Before Advice:方法之前执行
    2. After returning advice:方法return后执行
    3. After throwing advice:方法抛异常后执行
    4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后
    5. Around advice:这是功能最强大的Advice,可以自定义执行顺序

    看代码例子

    public class UserService {
    
        public void test() {
            System.out.println("test...");
            //throw new NullPointerException();
            //return "UserService------------test";
        }
    
        public void a() {
            System.out.println("a...");
        }
    
    }
    

    方法之前执行

    public class TestBeforeAdvice implements MethodBeforeAdvice {
    
    	@Override
    	public void before(Method method, Object[] args, Object target) throws Throwable {
    		System.out.println("方法执行前执行----MethodBeforeAdvice");
    		//这里不需要再写method.invoke(target,args);,会自动执行MethodInterceptorinvocation.proceed();,然后进入下一个链路
    		//method.invoke(target,args);
    	}
    }
    

    方法return后执行

    @Component
    public class TestAfterReturningAdvice implements AfterReturningAdvice {
    
       @Override
       public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
          System.out.println("方法return后执行-------AfterReturningAdvice");
       }
    
    }
    

    这是功能最强大的Advice,可以自定义执行顺序

    @Component
    public class TestAroundAdvice implements MethodInterceptor {
    
       @Override
       public Object invoke(MethodInvocation invocation) throws Throwable {
          System.out.println("方法执行Around前-------MethodInterceptor");
          //这里需要执行 invocation.proceed();
          Object proceed = invocation.proceed();
          System.out.println("方法执行Around后----------MethodInterceptor");
          return proceed;
       }
    }
    

    方法抛异常后执行

    public class TestThrowsAdvice implements ThrowsAdvice {
    
       //这里的异常类型要和被代理类抛出的类型一致时才执行 NullPointerException
       public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
          System.out.println("方法抛出异常后执行");
       }
    
    }
    

    测试

    public class AdviceDemo {
    
    	public static void main(String[] args) {
    		UserService userService = new UserService();
    
    		ProxyFactory proxyFactory = new ProxyFactory(userService);
    
    		//方法执行前执行
    		proxyFactory.addAdvice(new TestBeforeAdvice());
    
    		//环绕
    		proxyFactory.addAdvice(new TestAroundAdvice());
    
    		//方法执行后执行
    		proxyFactory.addAdvice(new TestAfterReturningAdvice());
    
    		//方法抛出异常后执行
    		//proxyFactory.addAdvice(new TestThrowsAdvice());
    
    		UserService proxy = (UserService) proxyFactory.getProxy();
    		proxy.test();
    
    	}
    }
    

    看结果

    方法执行前执行----MethodBeforeAdvice
    方法执行Around前-------MethodInterceptor
    test...
    方法return后执行-------AfterReturningAdvice
    方法执行Around后----------MethodInterceptor
    
    

    Advisor的理解

    跟Advice类似的还有一个Advisor的概念,一个Advisor是有一个Pointcut和一个Advice组成的,通过Pointcut可以指定要需要被代理的逻辑,按上面的例子,这两个方法都会被代理,被增强,那么我们现在可以通过Advisor,来控制到具体代理哪一个方法,比如:

    public class AdvisorDemo {
    
    	public static void main(String[] args) {
    		UserService userService = new UserService();
    
    		ProxyFactory proxyFactory = new ProxyFactory(userService);
    
    		//Advisor=Pointcut+Advice
    		proxyFactory.addAdvisor(new PointcutAdvisor() {
    
    			//切点
    			@Override
    			public Pointcut getPointcut() {
    				//做匹配
    				return new StaticMethodMatcherPointcut() {
    					@Override
    					public boolean matches(Method method, Class<?> targetClass) {
    						if ("test".equals(method.getName())){
    							return true;
    						}
    						return false;
    					}
    				};
    			}
    
    			//执行的具体代理逻辑
    			@Override
    			public Advice getAdvice() {
    				return new TestBeforeAdvice();
    			}
    
    			@Override
    			public boolean isPerInstance() {
    				return false;
    			}
    
    		});
    
    
    		UserService proxy = (UserService) proxyFactory.getProxy();
    		proxy.test();
    		proxy.a();
    
    	}
    }
    

    结果

    方法执行前执行----MethodBeforeAdvice
    test...
    a...
    

    上面代码表示,产生的代理对象,只有在执行test这个方法时才会被增强,会执行额外的逻辑,而在执行其他方法时是不会增强的。

    创建代理对象的方式

    上面介绍了Spring中所提供了ProxyFactory、Advisor、Advice、PointCut等技术来实现代理对象的创建,但是我们在使用Spring时,我们并不会直接这么去使用ProxyFactory,比如说,我们希望ProxyFactory所产生的代理对象能直接就是Bean,能直接从Spring容器中得到UserSerivce的代理对象,而这些,Spring都是支持的,只不过,作为开发者的我们肯定得告诉Spring,那些类需要被代理,代理逻辑是什么。

    BeanNameAutoProxyCreator

    我们可以通过BeanNameAutoProxyCreator来通过指定某个bean的名字,来对该bean进行代理

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
    	BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
    	beanNameAutoProxyCreator.setBeanNames("userSe*");
    	beanNameAutoProxyCreator.setInterceptorNames("testAroundAdvice");
        return beanNameAutoProxyCreator;
    }
    

    测试启动类

    public class AopTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAopConfig.class);
            UserService userService = (UserService) applicationContext.getBean("userService");
            userService.test();
    
        }
    
    }
    

    结果

    方法执行Around前-------MethodInterceptor
    test...
    方法执行Around后----------MethodInterceptor
    

    通过BeanNameAutoProxyCreator可以对批量的Bean进行AOP,并且指定了代理逻辑,指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的,但是BeanNameAutoProxyCreator的缺点很明显,它只能根据beanName来指定想要代理的Bean。

    DefaultAdvisorAutoProxyCreator

    通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的PointCut和Advice信息,确定要代理的Bean以及代理逻辑。

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(){
    	NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    	pointcut.addMethodName("test");
    
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
    	defaultPointcutAdvisor.setPointcut(pointcut);
    	defaultPointcutAdvisor.setAdvice(new ZhouyuAfterReturningAdvise());
    
        return defaultPointcutAdvisor;
    }
    
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    	
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    
    	return defaultAdvisorAutoProxyCreator;
    }
    

    结果

    test...
    方法return后执行-------AfterReturningAdvice
    

    但是,我们发现,通过这种方式,我们得依靠某一个类来实现定义我们的Advisor,或者Advise,或者Pointcut,那么这个步骤能不能更加简化一点呢?

    @Aspect

    对的,通过注解

    比如我们能不能只定义一个类,然后通过在类中的方法上通过某些注解,来定义PointCut以及Advice,可以的,比如:

    配置类上加上@EnableAspectJAutoProxy就可以了

    @EnableAspectJAutoProxy
    @Configuration
    @ComponentScan("com.yoocar.spring.aop")
    public class SpringAopConfig {
    
    
    }
    

    测试切面

    @Aspect
    @Component
    public class TestAspect {
    
        @Before("execution(public void com.yoocar.spring.aop.advice.UserService.test())")
        public void testAspectBefore(JoinPoint joinPoint) {
            System.out.println("testAspect-----Before");
        }
    
    }
    

    结果

    testAspect-----Before
    test...
    

    通过上面@Aspect这个类,我们就直接定义好了所要代理的方法(通过一个表达式),以及代理逻辑(被@Before修饰的方法),简单明了,

    这样对于Spring来说,它要做的就是来解析这些注解了,解析之后得到对应的Pointcut对象、Advice对象,生成Advisor对象,扔进ProxyFactory中,

    进而产生对应的代理对象,具体怎么解析这些注解就是@EnableAspectJAutoProxy注解所要做的事情了,

    后面详细分析。

    对Spring AOP的理解

    OOP表示面向对象编程,是一种编程思想,AOP表示面向切面编程,也是一种编程思想,而我们上面所描述的就是Spring为了让程序员更加方便的做到面向切面编程所提供的技术支持,换句话说,就是Spring提供了一套机制,可以让我们更加容易的来进行AOP,所以这套机制我们也可以称之为Spring AOP。

    但是值得注意的是,上面所提供的注解的方式来定义Pointcut和Advice,Spring并不是首创,首创是AspectJ,而且也不仅仅只有Spring提供了一套机制来支持AOP,还有比如 JBoss 4.0、aspectwerkz等技术都提供了对于AOP的支持。而刚刚说的注解的方式,Spring是依赖了AspectJ的,或者说,Spring是直接把AspectJ中所定义的那些注解直接拿过来用,自己没有再重复定义了,不过也仅仅只是把注解的定义赋值过来了,每个注解具体底层是怎么解析的,还是Spring自己做的,所以我们在用Spring时,如果你想用@Before、@Around等注解,是需要单独引入aspecj相关jar包的,比如:

    AOP中的概念

    上面我们已经提到Advisor、Advice、PointCut等概念了,还有一些其他的概念,首先关于AOP中的概念本身是比较难理解的,Spring官网上是这么说的:

    Let us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring used its own terminology

    意思是,AOP中的这些概念不是Spring特有的,不幸的是,AOP中的概念不是特别直观的,但是,如果Spring重新定义自己的那可能会导致更加混乱

    1. Aspect:表示切面,比如被@Aspect注解的类就是切面,可以在切面中去定义Pointcut、Advice等等
    2. Join point:表示连接点,表示一个程序在执行过程中的一个点,比如一个方法的执行,比如一个异常的处理,在Spring AOP中,一个连接点通常表示一个方法的执行。
    3. Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型,后面详细讨论,在很多AOP框架中,包括Spring,会用Interceptor拦截器来实现Advice,并且在连接点周围维护一个Interceptor链
    4. Pointcut:表示切点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上
    5. Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现
    6. Target object:目标对象,被代理对象
    7. AOP proxy:表示代理工厂,用来创建代理对象的,在Spring Framework中,要么是JDK动态代理,要么是CGLIB代理
    8. Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP

    Advice在Spring AOP中对应API

    上面说到的Aspject中的注解,其中有五个是用来定义Advice的,表示代理逻辑,以及执行时机:

    • @Before
    • @AfterReturning
    • @AfterThrowing
    • @After
    • @Around

    我们前面也提到过,Spring自己也提供了类似的执行实际的实现类:

    • 接口MethodBeforeAdvice,继承了接口BeforeAdvice
    • 接口AfterReturningAdvice
    • 接口ThrowsAdvice
    • 接口AfterAdvice
    • 接口MethodInterceptor

    Spring会把五个注解解析为对应的Advice类:

    • @Before:AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice
    • @AfterReturning:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice
    • @AfterThrowing:AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor
    • @After:AspectJAfterAdvice,实际上就是一个MethodInterceptor
    • @Around:AspectJAroundAdvice,实际上就是一个MethodInterceptor

    TargetSource的使用

    在我们日常的AOP中,被代理对象就是Bean对象,是由BeanFactory给我们创建出来的,但是Spring AOP中提供了TargetSource机制,可以让我们用来自定义逻辑来创建被代理对象

    比如@Lazy注解,当加在属性上时,会产生一个代理对象赋值给这个属性,产生代理对象的代码为:

    protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
    		BeanFactory beanFactory = getBeanFactory();
    		Assert.state(beanFactory instanceof DefaultListableBeanFactory,
    				"BeanFactory needs to be a DefaultListableBeanFactory");
    		final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
    
    		TargetSource ts = new TargetSource() {
    			@Override
    			public Class<?> getTargetClass() {
    				return descriptor.getDependencyType();
    			}
    			@Override
    			public boolean isStatic() {
    				return false;
    			}
    			@Override
    			public Object getTarget() {
    				Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
    				Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
    				if (target == null) {
    					Class<?> type = getTargetClass();
    					if (Map.class == type) {
    						return Collections.emptyMap();
    					}
    					else if (List.class == type) {
    						return Collections.emptyList();
    					}
    					else if (Set.class == type || Collection.class == type) {
    						return Collections.emptySet();
    					}
    					throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
    							"Optional dependency not present for lazy injection point");
    				}
    				if (autowiredBeanNames != null) {
    					for (String autowiredBeanName : autowiredBeanNames) {
    						if (dlbf.containsBean(autowiredBeanName)) {
    							dlbf.registerDependentBean(autowiredBeanName, beanName);
    						}
    					}
    				}
    				return target;
    			}
    			@Override
    			public void releaseTarget(Object target) {
    			}
    		};
    
    		ProxyFactory pf = new ProxyFactory();
    		pf.setTargetSource(ts);
    		Class<?> dependencyType = descriptor.getDependencyType();
    		if (dependencyType.isInterface()) {
    			pf.addInterface(dependencyType);
    		}
    		return pf.getProxy(dlbf.getBeanClassLoader());
    	}
    

    这段代码就利用了ProxyFactory来生成代理对象,以及使用了TargetSource,以达到代理对象在执行某个方法时,调用TargetSource的getTarget()方法实时得到一个被代理对象

    ProxyFactory选择动态方式原理

    //获取代理对象
    PeopleInterface peopleProxy = (PeopleInterface) factory.getProxy();
    

    ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术源码

    public Object getProxy() {
    	//跟createAopProxy
    	return createAopProxy().getProxy();
    }
    

    跟进去

    protected final synchronized AopProxy createAopProxy() {
       if (!this.active) {
          activate();
       }
       //createAopProxy创建代理对象
       return getAopProxyFactory().createAopProxy(this);
    }
    

    跟进去

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
       //isOptimize设置为true和isProxyTargetClass的true时一般使用Cglib,判断是否有添加接口的代码setInterfaces()
       if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
          Class<?> targetClass = config.getTargetClass();
          if (targetClass == null) {
             throw new AopConfigException("TargetSource cannot determine target class: " +
                   "Either an interface or a target is required for proxy creation.");
          }
          //被代理对象是否是接口类型.或者是jdk动态代理产生的代理类
          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
             return new JdkDynamicAopProxy(config);
          }
          //Cglib
          return new ObjenesisCglibAopProxy(config);
       }
       else {
          return new JdkDynamicAopProxy(config);
       }
    }
    

    代理对象创建过程

    JdkDynamicAopProxy

    1. 在构造JdkDynamicAopProxy对象时,会先拿到被代理对象自己所实现的接口,并且额外的增加SpringProxy、Advised、DecoratingProxy三个接口,组合成一个Class[],并赋值给proxiedInterfaces属性
    2. 并且检查这些接口中是否定义了equals()、hashcode()方法
    3. 执行Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理对象,JdkDynamicAopProxy作为InvocationHandler,代理对象在执行某个方法时,会进入到JdkDynamicAopProxy的invoke()方法中

    看下JdkDynamicAopProxy的代理对象创建过程

    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       Object oldProxy = null;
       boolean setProxyContext = false;
       //TargetSource机制,可以让我们用来自定义逻辑来创建被代理对象
       TargetSource targetSource = this.advised.targetSource;
       Object target = null;
    
       try {
          //如果目标对象没有定义equals方法,则直接调用,不走代理逻辑
          if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
             // The target does not implement the equals(Object) method itself.
             return equals(args[0]);
          }
          //如果目标对象没有定义hashCode方法,则直接调用,不走代理逻辑
          else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
             // The target does not implement the hashCode() method itself.
             return hashCode();
          }
          else if (method.getDeclaringClass() == DecoratingProxy.class) {
             //得到代理对象的类型
             // There is only getDecoratedClass() declared -> dispatch to proxy config.
             return AopProxyUtils.ultimateTargetClass(this.advised);
          }
          else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                method.getDeclaringClass().isAssignableFrom(Advised.class)) {
             // Service invocations on ProxyConfig with the proxy config...
             return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
          }
    
          Object retVal;
          //如果ProxyFactory的exposeProxy属性为true时,将代理对象放在ThreadLocal<Object> currentProxy
          if (this.advised.exposeProxy) {
             // Make invocation available if necessary.
             oldProxy = AopContext.setCurrentProxy(proxy);
             setProxyContext = true;
          }
    
          // Get as late as possible to minimize the time we "own" the target,
          // in case it comes from a pool.
          //被代理对象及其class对象
          target = targetSource.getTarget();
          Class<?> targetClass = (target != null ? target.getClass() : null);
    
          //代理对象在执行方法时 ,根据方法筛选出对应的Advisor,并适配成Interception
          // Get the interception chain for this method.
          List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
          // Check whether we have any advice. If we don't, we can fallback on direct
          // reflective invocation of the target, and avoid creating a MethodInvocation.
          if (chain.isEmpty()) {
             // We can skip creating a MethodInvocation: just invoke the target directly
             // Note that the final invoker must be an InvokerInterceptor so we know it does
             // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
             Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
             retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
          }
          else {
             //封装成MethodInvocation
             // We need to create a method invocation...
             MethodInvocation invocation =
                   new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
             //在这里执行MethodInvocation的链路
             // Proceed to the joinpoint through the interceptor chain.
             retVal = invocation.proceed();
          }
    
          // Massage return value if necessary.
          Class<?> returnType = method.getReturnType();
          if (retVal != null && retVal == target &&
                returnType != Object.class && returnType.isInstance(proxy) &&
                !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
             // Special case: it returned "this" and the return type of the method
             // is type-compatible. Note that we can't help if the target sets
             // a reference to itself in another returned object.
             retVal = proxy;
          }
          else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
             throw new AopInvocationException(
                   "Null return value from advice does not match primitive return type for: " + method);
          }
          return retVal;
       }
       finally {
          if (target != null && !targetSource.isStatic()) {
             // Must have come from TargetSource.
             targetSource.releaseTarget(target);
          }
          if (setProxyContext) {
             // Restore old proxy.
             AopContext.setCurrentProxy(oldProxy);
          }
       }
    }
    

    跟List

  • 相关阅读:
    iOS编译FFmpeg、kxmovie实现视频播放 (转载)
    CocoaPods 安装 使用
    如何做优化,UITabelView才能更加顺滑 (转载)
    iOS 保持界面流畅的技巧 (转载)
    ar命令详解
    ios 静态库冲突的解决办法
    【原】IOS合并lib(.a)库的终极可用方法(可用于解决duplicate symbol静态库冲突)
    react-native 学习之TextInput组件篇
    react-native 学习之Image篇
    js 对Array的补充
  • 原文地址:https://www.cnblogs.com/lusaisai/p/15983038.html
Copyright © 2020-2023  润新知