转载

一文搞懂Spring-AOP原理

  • PointCut这个接口有两部分组成,分别是 ClassFilterMethodMatcher ,其实可以很好的理解,如何定义一个切入点?我们在定义切入点的时候,就是想对某一个类的全部方法,或者对某一个类的部方法进行切入,因此在判断能否作用到方法上的时候,先判断是否类能够匹配(ClassFilter的活),之后再判断方法是否匹配(MethodMatcher的活)。
  • PointCut的实现类有很多,其中比较重要的是AOP使用的 AspectJExpressionPointcut 【这个类主要是解析execution表达式的,这个类同时实现了ClassFilter和MethodMatcher,具备了两者的功能,因此可以直接使用该类进行切入点的匹配】、 AnnotationMatchingPointcut 【注解的PointCut,主要用来匹配注解,底层使用就是 AnnotationMethodMatcherAnnotationMethodClassFilter ,后续会讲到】
  • 源码如下:

    public interface Pointcut{
    	//返回一个ClassFilter
    	ClassFiltergetClassFilter();
    
    	//返回一个MethodMatcher
    	MethodMatchergetMethodMatcher();
    
    
    	//TruePointCut,对应任何的方法都是匹配(总是匹配)
    	Pointcut TRUE = TruePointcut.INSTANCE;
    }
    
  • AspectJExpressionPointcut 演示如下:

@Test
 public void testAspectJExpressionPointCut()throws NoSuchMethodException {
     AspectJExpressionPointcut expressionPointcut = new AspectJExpressionPointcut();
     //设置aspectj表达式,这个比较常用的表达式
     expressionPointcut.setExpression("execution(* cn.tedu.demo.service.UserService.addUser(..))");
     //匹配类
     boolean b = expressionPointcut.matches(UserService.class);
     //直接调用matches匹配方法
     boolean a = expressionPointcut.matches(UserService.class.getDeclaredMethod("addUser", User.class), UserService.class);
     System.out.println(a+"--->"+b);
 }
  • AnnotationMatchingPointcut的演示如下:
    @Test
    public void testAnnotationMatchingPointcut()throws NoSuchMethodException {
        //第一个参数是注解,第二参数表示是否在接口和父类的查找该注解
        AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(Transactional.class, false);
        //匹配方法上是否有@Transactional注解
        boolean a = pointcut.getMethodMatcher().matches(UserService.class.getDeclaredMethod("addUser", User.class), UserService.class);
        //匹配类上是否有@Transactional注解
        boolean b = pointcut.getClassFilter().matches(UserService.class);
        System.out.println(a+"--->"+b);
    }
    

PointCuts

  • 类似于MethodMatchers和ClassFilters,其中同样有union等,作用就是提供了一个matches方法,不需要自己写步骤先比较Class,再比较Method等操作,当然还有一些便捷的功能。
    @Test
    public void testPointcuts()throws NoSuchMethodException {
        AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(Transactional.class, false);
        Class cls=UserService.class;
        Method method = cls.getDeclaredMethod("addUser", User.class);
        //调用matches方法,判断UserService的addUser方法是否有@Transactional注解
        boolean matches = Pointcuts.matches(annotationMatchingPointcut, method, cls);
        System.out.println(matches);
    
    }
    

ClassFilter

  • 类过滤器,就是判断类是否匹配
@FunctionalInterface
public interface ClassFilter{

	//判断方法
	boolean matches(Class<?> clazz);
	
    //定义一个总是匹配的TrueClassFilter,其实就是matches方法总是返回true
	ClassFilter TRUE = TrueClassFilter.INSTANCE;

}
  • ClassFilter在spring底层有许多实现的类,比如AnnotationClassFilter(匹配指定注解)、TrueClassFilter(全部匹配)、AspectJExpressionPointcut(Aspect表达式匹配,APO重要的组件)

  • 实例:使用AnnotationClassFilter测试该类是否有 @Transactional 注解

    • 该类有一个属性 checkInherited ,如果为false,那么只检查当前类是否有对应的注解,为true,那么会检查父类或者实现的接口存在,默认为false
       @Test
      public void testAnnotationClassFilter(){
          //指定checkInherited为true,会同时检查该类和父类及其实现的接口是否存在Transactional注解
          AnnotationClassFilter annotationClassFilter = new AnnotationClassFilter(Transactional.class, true);
          boolean matches = annotationClassFilter.matches(UserServiceImpl.class);
          System.out.println(matches);
         
      }
      
  • 我们也可以自定义自己的ClassFilter, 只需要实现其中的接口方法即可,如下:

    @Test
    public void testCustomClassFilter(){
        //自定义一个classFilter,判断指定的类是否是UserServiceImpl的接口或者父类或者同类
        ClassFilter customFilter =cls-> cls.isAssignableFrom(UserServiceImpl.class);
        boolean matches = customFilter.matches(UserService.class);
        System.out.println(matches);
    }
    

ClassFilters

  • 该抽象类中有两个ClassFilter,分别是 UnionClassFilter 【满足其中一个即返回true】、 IntersectionClassFilter 【必须满足所有的ClassFilter才返回true】
  • 同样的对应有两个静态方法上面的两个Filter,如下:
    public static ClassFilter union(ClassFilter cf1, ClassFilter cf2)
    public static ClassFilter intersection(ClassFilter cf1, ClassFilter cf2)
    
  • 实例
    @Test
        public void testClassFilters(){
            //类或者接口上必须有Transactional注解
            AnnotationClassFilter annotationClassFilter = new AnnotationClassFilter(Transactional.class,false);
            //类或者接口必须是UserServiceImpl的父类或者接口或者同类
            ClassFilter customFilter =cls-> cls.isAssignableFrom(UserServiceImpl.class);
            //返回unionFilter,只要满足上面的一个ClassFilter即返回true
            ClassFilter unionFilter = ClassFilters.union(annotationClassFilter, customFilter);
            //返回intersectionFilter,必须满足上面两个ClassFilter才会返回true
            ClassFilter intersectionFilter = ClassFilters.intersection(annotationClassFilter, customFilter);
            boolean u = unionFilter.matches(UserService.class);
            boolean i = intersectionFilter.matches(UserService.class);
            System.out.println(u);
            System.out.println(i);
        }
    

MethodMatcher

  • ClassFilter是匹配类,MethodMatcher是用来匹配方法
  • MethodMatcher有两个matches方法,分别是两个参数和三个参数的,两个参数用于静态匹配,只有两个参数的匹配返回true,isRuntime方法true,才应该调用三个参数的方法。如果isRuntime返回false,那么不应该调用三个参数的matches
  • 接口的实现类有很多,如 StaticMethodMatcher 【只支持静态匹配,两个参数的matchs】、 AspectJExpressionPointcut 【AOP重要组件】、 TrueMethodMatcher 【总是匹配】、 AnnotationMethodMatcher 【注解匹配】

  • 实例如下:

@Test
public void testAnnotationMethodMatcher()throws NoSuchMethodException {
    //检测方法上是否标注了Transactional注解,false指定了不检查当前类父类和接口
    AnnotationMethodMatcher methodMatcher=new AnnotationMethodMatcher(Transactional.class,false);
    Class cls=UserService.class;
    Method method = cls.getDeclaredMethod("addUser", User.class);
    //两个参数的mathces,三个参数的不支持【继承了StaticMethodMatcher】
    boolean matches = methodMatcher.matches(method, cls);
    System.out.println(matches);
}
  • 当然也是可以自定义实现类,这里和上面的ClassFilter的差不多,就不再写了,自己发挥想象力

MethodMatchers

  • 同ClassFilters功能一样,其中提供了 UnionMethodMatcher类 【只要匹配一个即返回true】, IntersectionMethodMatcher 【】
  • 此处不再演示

Advice

  • 通知的接口,在aop中的每一个通知注解都有对应的接口,比如 BeforeAdviceAfterAdvice
  • Advice的默认实现抽象类是 AbstractAspectJAdvice ,各种AspectJ的通知都会继承并拓展该类,其中封装了有关通知的全部信息,比如方法名称、方法Method对象、PointCut、Jpoint、pointCut表达式等等信息,其中最重要的一个方法就是 protected Object invokeAdviceMethodWithGivenArgs(Object[] args) ,该方法用于调用通知方法。
  • 其中关于AspectJ的五种通知方法,类的命名方式是 AspectJXxxAdvice ,继承抽象类 AbstractAspectJAdvice
  • 比如 AspectAfterAdvice 这个实现类,其中重要的方法就是invok,源码如下:
    • 通过源码就可以看出在方法之后执行是怎样的过程,先调用被增强的方法【原方法】、再调用被@After标注的通知方法。
public Object invoke(MethodInvocation mi)throws Throwable {
		try {
            //先执行被增强的方法
			return mi.proceed();
		}
		finally {
            //再执行通知方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

Advisor

  • 顾问的意思,其中封装了Advice(通知)。

PointcutAdvisor

AspectJExpressionPointcutAdvisor

proxyFactory

org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config)throws AopConfigException {
		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);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
            //创建Cglib动态代理
			return new JdkDynamicAopProxy(config);
		}
	}

示例

public class ProxyFactoryTest{

    /**
     * 自定义一个BeforeAdvice
     */
    public static class CustomBeforAdviceimplements MethodBeforeAdvice{
        @Override
        public void before(Method method, Object[] args, Object target)throws Throwable {
            String name = method.getName();
            if (StringUtils.equals(name,"addUser")){
                System.out.println("在addUser之前执行");
            }else{
                System.out.println("other");
            }
        }
    }
    public static class Log{
        public void before(){
            System.out.println("在之前执行");
        }
    }

    @Test
    public void test1(){
        UserService userService=new UserServiceImpl();
        //创建proxyFactory
        ProxyFactory factory = new ProxyFactory(userService);
        //创建自定义的BeforeAdvice
        MethodBeforeAdvice advice=new CustomBeforAdvice();
        //将Advice添加到proxyFactory中
        factory.addAdvice(advice);
        //获取代理对象
        UserService proxy = (UserService) factory.getProxy();
        proxy.addUser(new User(""));
    }



    @Test
    public void test2()throws NoSuchMethodException {
        UserService userService=new UserServiceImpl();
        //创建proxyFactory
        ProxyFactory factory = new ProxyFactory(userService);
        Class aspectCls=Log.class;
        Method aspectMethod = aspectCls.getMethod("before");
        //构建aspectJ表达式切入点
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(* cn.tedu.demo.service.UserService.addUser(..))");
        //创建AspectInstanceFactory(切面实例工厂)
        AspectInstanceFactory aspectInstanceFactory=new SimpleAspectInstanceFactory(aspectCls);
        AspectJMethodBeforeAdvice advice=new AspectJMethodBeforeAdvice(aspectMethod,aspectJExpressionPointcut,aspectInstanceFactory);
        //创建Advisor,其中封装了Advice和Advisor
        Advisor advisor = new AspectJPointcutAdvisor(advice);
        ArrayList<Advisor> advisors = Lists.newArrayList(advisor);
        //添加ExposeInvocationInterceptor到advisor中,这个不是必须的,但是使用AspectJ expression pointcut是必须的
        AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
        //将advisor添加到ProxyFactory中
        factory.addAdvisors(advisors);
        UserService proxy= (UserService) factory.getProxy();
        proxy.addUser(new User("chen"));


    }
}

@EnableAspectJAutoProxy

  • @EnableAspectJAutoProxy 该注解中可以看出使用了 @Import(AspectJAutoProxyRegistrar.class) ,因此实际作用的类就是 AspectJAutoProxyRegistrar
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

AspectJAutoProxyRegistrar

ImportBeanDefinitionRegistrar
AnnotationAutoProxyCreator
class AspectJAutoProxyRegistrarimplements ImportBeanDefinitionRegistrar{

	/**
	* 向容器中注入AnnotationAutoProxyCreator
	*/
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//调用方法注册AnnotationAutoProxyCreator
		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        //获取@EnableAspectJAutoProxy注解中两个属性的值
		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        //判断注解属性的值
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}

AnnotationAutoProxyCreator

SmartInstantiationAwareBeanPostProcessor

一文搞懂Spring-AOP原理

  • 创建代理对象的代码如下:

    • 真正的实现在 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
      • advisedBeans:存放所有的Bean,value是Boolean类型的值,如果为false表示不需要代理,反之则需要代理
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey){
    		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
    			return bean;
    		}
        	//如果为false,直接返回,不需要代理
    		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
    			return bean;
    		}
        	//判断是否是基础的切面类
    		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
    			this.advisedBeans.put(cacheKey, Boolean.FALSE);
    			return bean;
    		}
    
    		// 获取适用的Advisor
    		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    		if (specificInterceptors != DO_NOT_PROXY) {
    			this.advisedBeans.put(cacheKey, Boolean.TRUE);
                //创建代理对象
    			Object proxy = createProxy(
    					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
    			this.proxyTypes.put(cacheKey, proxy.getClass());
    			return proxy;
    		}
    
    		this.advisedBeans.put(cacheKey, Boolean.FALSE);
    		return bean;
    	}
    
    
    //org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
    protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
    			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
    
    		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    		}
    		//创建代理工厂
    		ProxyFactory proxyFactory = new ProxyFactory();
    		proxyFactory.copyFrom(this);
    		
    		if (!proxyFactory.isProxyTargetClass()) {
    			if (shouldProxyTargetClass(beanClass, beanName)) {
    				proxyFactory.setProxyTargetClass(true);
    			}
    			else {
    				evaluateProxyInterfaces(beanClass, proxyFactory);
    			}
    		}
    
    		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    		proxyFactory.addAdvisors(advisors);
    		proxyFactory.setTargetSource(targetSource);
    		customizeProxyFactory(proxyFactory);
    
    		proxyFactory.setFrozen(this.freezeProxy);
    		if (advisorsPreFiltered()) {
    			proxyFactory.setPreFiltered(true);
    		}
    
    		return proxyFactory.getProxy(getProxyClassLoader());
    	}
    

BeanFactoryAspectJAdvisorsBuilder

AbstractAdvisorAutoProxyCreator

AspectJAdvisorFactory

  • Advisor工厂,主要是用来构造Advisor的,在BeanFactoryAspectJAdvisorsBuilder中被应用。
  • ReflectiveAspectJAdvisorFactory 是其实现类,AOP中就是使用该类构造Advisor
  • 其中最重要的两个方法如下:
    private List<Method> getAdvisorMethods(Class<?> aspectClass)
    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory)
    

JdkDynamicAopProxy

  • JDK的动态调用的主要类,实现了AopProxy、InvocationHandler
  • 重要的属性:
    • private final AdvisedSupport advised :其中封装了代理类的属性,其实就是一个ProxyFactory,包括目标类,目标方法、advisor等信息。
  • 重要方法:
    • public Object invoke(Object proxy, Method method, Object[] args) :方法调用的类,实现了InvocationHandler的方法

MethodInterceptor

Object invoke(MethodInvocation invocation) throws Throwable

AspectJAfterAdvice【示例】

  • 该类实现了MethodInterceptor,其中的Invoke实现如下:
    • 其中的 mi.proceed() 这个方法,是责任链模式的重要方法。
@Override
	public Object invoke(MethodInvocation mi)throws Throwable {
		try {
            //调用其他的拦截器【因为这个拦截器是在方法之后执行的】
			return mi.proceed();
		}
		finally {
            //最终调用通知方法
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

MethodInvocation

  • 方法调用器,其中一个实现类是AOp中非常重要的组件(ReflectiveMethodInvocation)。

ReflectiveMethodInvocation

  • 该类在spring中的大致描述就是通过反射调用目标方法,是spring中内部使用的类。
  • 该类其中的重要的方法就是 proceed ,通过责任链的模式执行拦截器中的方法,和MethodInterceptor完美的诠释了责任链设计模式。源码如下:
    • 其实最重要的就是在内部调用了拦截器的invoke方法,但是在拦截器的invoke方法中还会递归的执行的proceed方法,这样的配置就完成了责任链的模式。
public Object proceed()throws Throwable {
		// 标记拦截器链执行的位置,初始值是-1,递归的结束条件
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {		
            //拦截器都执行完成了,那么通过反射执行目标方法
			return invokeJoinpoint();
		}
		//获取拦截器
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    	//判断拦截器的类型
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {

				return proceed();
			}
		}
		else {
			//调用拦截器的invoke方法
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
  • 实例如下:
@Test
    public void test1()throws Throwable {
        //目标对象
        UserService userService=new UserServiceImpl();
        //新建一个ProxyFactory,创建代理
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(userService);
        //设置接口,否则使用的是cglib代理
        factory.setInterfaces(UserService.class);
        //获取代理对象
        Object proxy = factory.getProxy();
        //切面
        Class aspectCls=LogAspect.class;
        //通知方法
        Method aspectMethod=aspectCls.getDeclaredMethod("afterAdvice");
        //切面对象
        final Object aspectObj=new LogAspect();
        //新建一个拦截器
        MethodInterceptor afterInterceptor=new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation)throws Throwable {
                CustomeInvocation ref=(CustomeInvocation)invocation;
                try{
                    //执行其他的拦截器
                    return invocation.proceed();
                }finally {
                    //最后执行切面的方法
                    ref.getAspectMethod().invoke(ref.getAspectObj(), ref.getAspectArgs());
// System.out.println("方法之后执行");
                }
            }
        };
        //创建拦截器链
        List<Object> interceptors=new ArrayList<>();
        interceptors.add(afterInterceptor);
        Method targetMethod=UserService.class.getMethod("addUser", User.class);
        Object[] args=new Object[]{new User("陈加兵")};
        CustomeInvocation invocation = new CustomeInvocation(proxy, userService, targetMethod, args, UserService.class,interceptors,aspectCls,aspectMethod,aspectObj,new Object[]{});
        invocation.proceed();
    }

    /**
     * 自定义一个Invocation,因为ReflectiveMethodInvocation是spring内部使用的,构造方法protected
     */
    public static class CustomeInvocationextends ReflectiveMethodInvocation{
        private Method aspectMethod;
        private Class aspcetCls;
        private Object aspectObj;
        private Object[] aspectArgs;
        /**
         * @param proxy 代理
         * @param target 目标对象
         * @param method 目标方法
         * @param arguments 参数
         * @param targetClass 目标类
         * @param aspectMethod 通知方法
         * @param  aspctCls 切面类
         * @param  aspectObj 切面对象
         * @param interceptorsAndDynamicMethodMatchers 拦截器
         */
        public CustomeInvocation(Object proxy, Object target, Method method, Object[] arguments, Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers,Class aspctCls,Method aspectMethod,Object aspectObj,Object[] aspectArgs){
            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
            this.aspectMethod=aspectMethod;
            this.aspcetCls=aspctCls;
            this.aspectObj=aspectObj;
            this.aspectArgs=aspectArgs;
        }
    }

JDK动态代理示例

public class JDKDynamicProxy{
    public static interface Subject{
        int add(int a,int b);
    }

    public static class CustomSubjectimplements Subject{
        @Override
        public int add(int a, int b){
            System.out.println("执行加法计算");
            return a+b;
        }
    }

    /**
     * 自定义的InvocationHandler
     */
    public static class CustomInvocationHandlerimplements InvocationHandler{

        /**
         * 目标对象
         */
        private Object targetObject;

        public CustomInvocationHandler(Object targetObject){
            this.targetObject = targetObject;
        }

        /**
         * @param proxy 代理对象
         * @param method 真正执行的方法
         * @param args 方法参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
            String methodName = method.getName();
            if (methodName.equals("add")){
                System.out.println("invok调用");
                Object invoke = method.invoke(targetObject, args);
                return invoke;
            }
            return null;
        }
    }

    @Test
    public void test(){
        Subject subject=new CustomSubject();
        CustomInvocationHandler customInvocationHandler = new CustomInvocationHandler(subject);
        Subject proxy= (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Subject.class}, customInvocationHandler);
        int count = proxy.add(1, 2);
        System.out.println(count);
    }
}
原文  https://chenjiabing666.github.io/2019/07/19/一文搞懂Spring-AOP原理/
正文到此结束
Loading...