五Spring-AOP--3AOP动态代理涉及的类

五Spring-AOP--3AOP动态代理涉及的类

5.5 Spring AOP动态代理涉及的类

5.5.1 ProxyConfig

用于创建代理的配置的父类,以确保所有代理创建者具有一致的属性

public class ProxyConfig implements Serializable {

	// 标记是否直接对目标类进行代理,而不是通过接口产生代理
	private boolean proxyTargetClass = false;
	// 标记是否对代理进行优化。true:那么在生成代理对象之后,如果对代理配置进行了修改,已经创建的代理对象也不会获取修改之后的代理配置。
	// 如果exposeProxy设置为true,即使optimize为true也会被忽略。
	private boolean optimize = false;
	// 标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
	//Advised接口其实就代表了被代理的对象(此接口是Spring AOP提供,它提供了方法可以对代理进行操作,比如移除一个切面之类的),它持有了代理对象的一些属性,通过它可以对生成的代理对象的一些属性进行人为干预
	// 默认情况,我们可以这么完 Advised target = (Advised) context.getBean("opaqueTest"); 从而就可以对该代理持有的一些属性进行干预勒   若此值为true,就不能这么玩了
	boolean opaque = false;
	//标记代理对象是否应该被aop框架通过AopContext以ThreadLocal的形式暴露出去。
	//当一个代理对象需要调用它【自己】的另外一个代理方法时,这个属性将非常有用。默认是是false,以避免不必要的拦截。
	boolean exposeProxy = false;
	//标记是否需要冻结代理对象,即在代理对象生成之后,是否允许对其进行修改,默认为false.
	// 当我们不希望调用方修改转换成Advised对象之后的代理对象时,就可以设置为true 给冻结上即可
	private boolean frozen = false;
     
     //从其他config对象中,复制配置信息到当前config
     public void copyFrom(ProxyConfig other) {
		Assert.notNull(other, "Other ProxyConfig object must not be null");
		this.proxyTargetClass = other.proxyTargetClass;
		this.optimize = other.optimize;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.opaque = other.opaque;
	}
     
}

proxyConfig有两大实现类,如下:

image-20230310115820750

advisedSupport负责管理某个beanclass的所有切面advisor和拦截器interceptor的管理,主要实现类是proxyFactory,创建代理的工厂类(创建代理,需要知道target,method,interface等信息,以及需要知道advice、pointcut等切面信息,将这些增强添加到target上,完成代理类的创建工作);

ProxyProcessorSupport负责

5.5.2 Advised

image-20220427195914626

注意本质:

Advice: 通知,拦截器(是具体的一个增强方法)

**Advisor: 通知 + 切入点的适配器,每一个服务类(如logging),其内定义多个增强方法,每个可以根据advice+pointcut,构成一个advisor,也叫做切面 **

Advised: 包含所有的Advisor 和 Advice,提供add和remove方法,负责对两个对象的管理工作

该advised的实现类最终是ProxyFactory,用来创建代理目标targetsource的proxy。proxy需要注入包括拦截器、advice等内容。因此,advised接口的作用,就是保存一个代理对象target需要的所有的相关配置信息,如这个targetsource的所有的interceptor、advice等。

所有的代理对象都实现了该接口(我们就能够通过一个代理对象,获取这个代理对象怎么被代理出来的相关信息)

不管是JDKproxy,还是cglib proxy,代理出来的对象都实现了org.springframework.aop.framework.Advised接口;

image-20220427202534559

Addvised接口负责对advice和advisor的管理,包括add和remove操作方法;同时,还包括保存的代理的接口、targetsource代理的目标类(aop代理的是targetsource对象)。

该接口需要被实现,该class持有aop 的proxyFactory的配置。该configuration包括interceptros,Advisors,以及被代理的interface。任何从spring获取的aop的代理对象,都可以投给该advised接口(就是aop代理对象,实现该advised接口),允许对其AOP的advice等进行操作。

image-20220427203521303

主要作用:

该接口为proxyFactory提供对advice和advisor管理的方法。

public interface Advised extends TargetClassAware {

	boolean isFrozen();
	boolean isProxyTargetClass();
	//返回被代理了的接口们
	Class<?>[] getProxiedInterfaces();
	// 检查这个指定的接口是否被代理了。。。
	boolean isInterfaceProxied(Class<?> intf);
	// 设置一个源。只有isFrozen为false才能调用此方法
     //设置被代理的类(为targetSource)
	void setTargetSource(TargetSource targetSource);
	TargetSource getTargetSource();
}

5.5.2.1 AdvisedSupport

public class AdvisedSupport extends ProxyConfig implements Advised {
     
    //advisor链。当一个Advice添加,会被wrap成advisor后添加到当前list
	private List<Advisor> advisors = new ArrayList<>();
  
  /** method为key,List<advisorChain>为value的methodCache缓存对象 */
	private transient Map<MethodCacheKey, List<Object>> methodCache;
     
     //提供advisorChainFactory。factory提供
   AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
     
     // 这里需要注意的是:setTarget最终的效果其实也是转换成了TargetSource
	// 也就是说Spring最终代理的  是放进去TargetSource让它去处理
     //ProxyFactory中设置的target目标,最终会被包装成SingletonTargetSource对象
	public void setTarget(Object target) {
		setTargetSource(new SingletonTargetSource(target));
	}
	@Override
	public void setTargetSource(@Nullable TargetSource targetSource) {
		this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
	}
     
     //根据此配置,确定给定方法的MethodInterceptor列表
     //该方法用来获取代理的方法上,对应的有效的所有的拦截器interceptor链
     //将DefaultAdvisorChainFactory的方法代理到getInterceptorsAndDynamicInterceptionAdvice上
     	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
     //以待拦截的method对象,创建MethodCacheKey--缓存中的key
		MethodCacheKey cacheKey = new MethodCacheKey(method);
     //查询缓存
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
      
/**…………………………………………………………………………生成拦截器chain………………………………………………………………………………………… */
       //DefaultAdvisorChainFactory:生成通知器链的工厂,实现了interceptor链的获取过程
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
      //缓存中存储(MethodCacheKey(method),InterceptorsAndDynamicInterceptionAdvice)
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}

用于设置和保存下面三大信息:

  1. 设置被代理对象target
  2. 设置代理接口
  3. 设置通知advice

image-20220427213918839

注册被代理的目标对象、advice和需要代理的接口interface。

提供了使用proxyFactory获取aopProxy时候,设置代理对象的target和interface的方法。

[另外请详细见AdvisorChainFactory](#5.5.5.1 AdvisorChainFactory)

AdvisedSupport本身不会提供创建代理的任何方法,专注于生成拦截器链。委托给ProxyCreatorSupport去创建代理对象

5.5.2.2 ProxyCreatorSupport

注册和触发监听器,借助[DefaultAopProxyFactory](#5.5.4.1 DefaultAopProxyFactory)获取代理AopProxy(jdk和cglib动态代理的封装)。

public class ProxyCreatorSupport extends AdvisedSupport {

     //new了一个aopProxyFactory
     //通过DefaultAopProxyFactory创建aopProxy
	private AopProxyFactory aopProxyFactory;
	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}

     //包含对listener的add/remove的管理
	private final List<AdvisedSupportListener> listeners = new LinkedList<>();
     
     //子类调用该方法获取aop proxy。
     protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
      //委托给AopProxyFactory,获取aopProxyfactory,然后createAopProxy创建AopProxy
		return getAopProxyFactory().createAopProxy(this);
	}
  
     public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}

ProxyCreatorSupport继承AdvisedSupport,主要提供了createAopProxy方法,代理给[DefaultAopProxyFactory.createAopProxy()](#5.5.4.1 DefaultAopProxyFactory),用来得到用来生成代理对象的AopProxy对象(提供动态代理创建对象的类,包括cglib和JDK)。

该类的实现类,是三大创建代理对象的工厂proxyFactory:

image-20220428144439225

5.5.2.3 ProxyFactory

使用场景:

通过配置<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解@AspectJ的Aspectj风格的Aop代理。

public class ProxyFactory extends ProxyCreatorSupport {
     //丰富的构造函数,设置proxyFactory所需要的基本配置信息
     public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
		addInterface(proxyInterface);
		addAdvice(interceptor);
	}

     public Object getProxy() {
          return createAopProxy().getProxy();
     }
     
     public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}
     
     	// 注意:若调用此方法生成代理,就直接使用的是CGLIB的方式的
	public static Object getProxy(TargetSource targetSource) {
		if (targetSource.getTargetClass() == null) {
			throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setTargetSource(targetSource);
		proxyFactory.setProxyTargetClass(true);
		return proxyFactory.getProxy();
	}

提供获取代理proxy的能力——就是提供getProxy()方法。

注意:

proxyFactory同样与springIOC容器没有关系,可以手动创建代理并使用。但是,由于其所代理的target,是由new创建出来的,因此不能和springIOC容器融合,因此proxyFactory不像ProxyFactoryBean可以定制化方法,proxyFactory是由spring内部调用,会在autoProxyCreator(代理自动创建器)中使用。

例如:

    public static void main(String[] args) {
         //代理的对象需要new,不能依靠springIOC的自动注入bean,因此用作内部调用
        ProxyFactory proxyFactory = new ProxyFactory(new HelloServiceImpl());

        // 添加两个Advice,一个匿名内部类表示
        proxyFactory.addAdvice((AfterReturningAdvice) (returnValue, method, args1, target) ->
                System.out.println("AfterReturningAdvice method=" + method.getName()));
        proxyFactory.addAdvice(new LogMethodBeforeAdvice());
        
        HelloService proxy = (HelloService) proxyFactory.getProxy();
        proxy.hello();
    }

输出:
this is LogMethodBeforeAdvice
this is my method~~
AfterReturningAdvice method=hello

5.5.2.4 ProxyFactoryBean

通过该类可以自定义getObject方法,来获取代理的对象。

注意:

	private String[] interceptorNames;
此为注册的advice的名称。
如果用注释方式,@aspect内除了@pointcut,每个@before、@after等的方法名,最后会生成一个advice增强实例;
如果是非注释方式,该名称就是具体的实现类,如下:

     // 先定义一个前置通知
@Component("logMethodBeforeAdvice")
public class LogMethodBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("this is LogMethodBeforeAdvice");
    }
}

可见,构建拦截器链的过程interceptorNames——advice——advisor——methodInterceptor或者InterceptorAndDynamicMethodMatcher

public class ProxyFactoryBean extends ProxyCreatorSupport
		implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware {
	//需要植入target对象的advice的名称
	private String[] interceptorNames;
	private String targetName;
	//重要的转换类(适配器类)
	private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
	private transient BeanFactory beanFactory;
	//advisorchain是否初始化过
	private boolean advisorChainInitialized = false;
	//单例缓存
	private Object singletonInstance;

     //类似于spring中的factoryBean.getObject方法,实现该方法来获取真正的bean
    public Object getObject() throws BeansException {
		//就是根据我们配置的interceptorNames来获取对应需要植入的切面的bean,并却转化成Advisor。将当前target所有的
		//this.advisorChainInitialized:标示是否已进行过初始化,若以初始化则不再进行初始化。
		initializeAdvisorChain();
		
		//生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分
		if (isSingleton()) {
			//生成singleton的代理对象,这个方法是ProxyFactoryBean生成AOPProxy代理对象的调用入口
			return getSingletonInstance();
		}
		else {
			if (this.targetName == null) {
				logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			}
			// 生成原型的代理对象
			return newPrototypeInstance();
		}
	}
     
     //通过读取interceptorNames将BeanFactory工厂内对应的Advice,Advisor,MethodInterceptor
	//通过AdvisorAdapterRegistry.wrap(Advice,需要有对应的AdvisorAdapter的支持才可以转换)转换为Advisor然后加载到执行链条中
	private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
		if (this.advisorChainInitialized) {
			return;
		}

		if (!ObjectUtils.isEmpty(this.interceptorNames)) {
			// Globals can't be last unless we specified a targetSource using the property...
			// 最后一个不能是全局的suffix *,除非我们指定了targetSource之类的
			if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
				throw new AopConfigException("Target required after globals");
			}

			// Materialize interceptor chain from bean names.
			for (String name : this.interceptorNames) {
	
				// 如果拦截器的名称是以*结尾的,说明它要去全局里面都搜索出来
				// 全局:去自己容器以及父容器中找,类型为Advisor.class以及Interceptor.class所有的,名称是以这个名称为开头的prefix的Bean.
				// 最终也一样交给addAdvisorOnChainCreation(bean, name);   相当于一个批量处理吧  在特殊场景还是很有用处的
				if (name.endsWith(GLOBAL_SUFFIX)) {
					addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
							name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
				}
				
				// 绝大部分情况肯定都走这里:精确匹配
				else {
					Object advice;
					if (this.singleton || this.beanFactory.isSingleton(name)) {
						// 从容器里把这个Bean拿出来~~~~~~~~~~~~~
						advice = this.beanFactory.getBean(name);
					}
					// 多例的  这里每次都是new一个新的
					else {
						// It's a prototype Advice or Advisor: replace with a prototype.
						// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
						advice = new PrototypePlaceholderAdvisor(name);
					}
					// 这个方法的作用还挺大的:将advice对象添加到通知器链中
					//方法中首先会调用namedBeanToAdvisor(next)方法,将从ioc容器获取的普通对象转换成通知器Advisor对象,然后add加入factory的List<Advisor>对象中
					addAdvisorOnChainCreation(advice, name);
				}
			}
		}
		this.advisorChainInitialized = true;
	}


	private void addAdvisorOnChainCreation(Object next, String name) {
		// We need to convert to an Advisor if necessary so that our source reference
		// matches what we find from superclass interceptors.
		// 这里调用namedBeanToAdvisor做了一下适配:成统一的Advisor 
		Advisor advisor = namedBeanToAdvisor(next);
		addAdvisor(advisor);
	}
//namedBeanToAdvisor
	private Advisor namedBeanToAdvisor(Object next) {
		try {
			return this.advisorAdapterRegistry.wrap(next);
		}
	}
     
     //获取单例代理对象
	private synchronized Object getSingletonInstance() {
		// 如果是单例的,现在这里持有这个缓存  创建国就不会再创建了
		if (this.singletonInstance == null) {
			// 根据设置的targetName,去工厂里拿到这个bean对象(普通Bean被包装成SingletonTargetSource)
			this.targetSource = freshTargetSource();
			
			// 这一步是如果你手动没有去设置需要被代理的接口,Spring还是会去帮你找看你有没有实现啥接口,然后全部给你代理上。可见Spring的容错性是很强的
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				Class<?> targetClass = getTargetClass();
				if (targetClass == null) {
					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
				}
				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
			// Initialize the shared singleton instance.
			super.setFrozen(this.freezeProxy);
			// createAopProxy()方法就是父类ProxyCreatorSupport的方法
			// 其中JdkDynamicAopProxy和CglibAopProxy对getProxy()方法的实现,也请参考前面分析
			this.singletonInstance = getProxy(createAopProxy());
		}
		return this.singletonInstance;
	}
     
     	private synchronized Object newPrototypeInstance() {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
		}

		ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
		// The copy needs a fresh advisor chain, and a fresh TargetSource.
		TargetSource targetSource = freshTargetSource();
		copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
		if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			Class<?> targetClass = targetSource.getTargetClass();
			if (targetClass != null) {
				copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
		}
		copy.setFrozen(this.freezeProxy);

		if (logger.isTraceEnabled()) {
			logger.trace("Using ProxyCreatorSupport copy: " + copy);
		}
		return getProxy(copy.createAopProxy());
	}

以上是针对某个具体targetclass进行代理,并产生代理类。

开发示例如下:

1 与spring容器集成使用

// 先定义一个前置通知
@Component("logMethodBeforeAdvice")
public class LogMethodBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("this is LogMethodBeforeAdvice");
    }
}

// 注册一个代理Bean
//手动创建proxyFactoryBean,需要手动设置Target,Interfaces,InterceptorNames信息。
    @Bean
    public ProxyFactoryBean proxyFactoryBean(HelloService helloService) {
        ProxyFactoryBean factoryBean = new ProxyFactoryBean();

        //代理的目标对象  效果同setTargetSource(@Nullable TargetSource targetSource)
        // 此处需要注意的是,这里如果直接new,那么该类就不能使用@Autowired之类的注入  因此建议此处还是从容器中去拿
        // 因此可以写在入参上(这也是标准的写法~~)
        //factoryBean.setTarget(new HelloServiceImpl());
        factoryBean.setTarget(helloService);

        // setInterfaces和setProxyInterfaces的效果是相同的。设置需要被代理的接口,
        // 若没有实现接口,那就会采用cglib去代理
        // 需要说明的一点是:这里不设置也能正常被代理(若你没指定,Spring内部会去帮你找到所有的接口,然后全部代理上~~~~~~~~~~~~)  设置的好处是只代理指定的接口
        factoryBean.setInterfaces(HelloService.class);
        //factoryBean.setProxyInterfaces(new Class[]{HelloService.class});

        // 需要植入进目标对象的bean列表 此处需要注意:这些bean必须实现 org.aopalliance.intercept.MethodInterceptor或 org.springframework.aop.Advisor的bean ,配置中的顺序对应调用的顺序
        factoryBean.setInterceptorNames("logMethodBeforeAdvice");

        // 若设置为true,强制使用cglib,默认是false的
        //factoryBean.setProxyTargetClass(true);

        return factoryBean;
    }

// main方法测试:
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);

        //expected single matching bean but found 2: helloServiceImpl,proxyFactoryBean
        // 如果通过类型获取,会找到两个Bean:一个我们自己的实现类、一个ProxyFactoryBean所生产的代理类 而此处我们显然是希望要生成的代理类的  因此我们只能通过名称来(或者加上@Primary)
        //HelloService bean = applicationContext.getBean(HelloService.class);
        HelloService bean = (HelloService) applicationContext.getBean("proxyFactoryBean");
        bean.hello();
        
        System.out.println(bean); //com.fsx.service.HelloServiceImpl@4e50c791
        System.out.println(bean.getClass()); //class com.sun.proxy.$Proxy22 用得JDK的动态代理
        // 顺便说一句:这样也是没错得。因为Spring AOP代理出来的每个代理对象,都默认实现了这个接口(它是个标记接口)
        // 它这个也就类似于所有的JDK代理出来的,都是Proxy的子类是一样的思想~
        SpringProxy springProxy = (SpringProxy) bean;
    }

输出:
this is LogMethodBeforeAdvice
this is my method~~

注意区别:

 //expected single matching bean but found 2: helloServiceImpl,proxyFactoryBean
    // 如果通过类型获取,会找到两个Bean:一个我们自己的实现类、一个ProxyFactoryBean所生产的代理类 而此处我们显然是希望要生成的代理类的  因此我们只能通过名称来(或者加上@Primary)
    //HelloService bean = applicationContext.getBean(HelloService.class);
    HelloService bean = (HelloService) applicationContext.getBean("proxyFactoryBean");

2 脱离spring容器使用

proxyFactoryBean的生成代理的核心功能getProxy在父类ProxyCreatorSupport上,与容器无关,因此可以摆脱springIOC而独立手动创建使用。

此时,需要设置target(如果target有接口,设置interface),然后需要手动创建advice并转换为advisor,然后proxyFactoryBean.addAdvisor(advisor)添加。最后可以通过getObject获取aop增强的代理对象。

public class Main {

    public static void main(String[] args) {
        String pointcutExpression = "execution( int com.fsx.maintest.Person.run() )";

        // =============================================================
        //因为我们要使用AspectJ,所以此处采用AspectJProxyFactory,当然你也可以使用和容器相关的ProxyFactoryBean
        ProxyFactoryBean factory = new ProxyFactoryBean();
        factory.setTarget(new Person());

        //AspectJProxyFactory factory = new AspectJProxyFactory(new Person());

        //声明一个aspectj切点,一张切面
        AspectJExpressionPointcut cut = new AspectJExpressionPointcut();
        cut.setExpression(pointcutExpression); // 设置切点表达式

        // 声明一个通知(此处使用环绕通知 MethodInterceptor )
        Advice advice = (MethodInterceptor) invocation -> {
            System.out.println("============>放行前拦截...");
            Object obj = invocation.proceed();
            System.out.println("============>放行后拦截...");
            return obj;
        };

        //切面=切点+通知
        // 它还有个构造函数:DefaultPointcutAdvisor(Advice advice); 用的切面就是Pointcut.TRUE,所以如果你要指定切面,请使用自己指定的构造函数
        // Pointcut.TRUE:表示啥都返回true,也就是说这个切面作用于所有的方法上/所有的方法
        // addAdvice();方法最终内部都是被包装成一个 `DefaultPointcutAdvisor`,且使用的是Pointcut.TRUE切面,因此需要注意这些区别
        Advisor advisor = new DefaultPointcutAdvisor(cut, advice);
        factory.addAdvisor(advisor);
        //Person p = factory.getProxy();
        Person p = (Person) factory.getObject();

        // 执行方法
        p.run();
        p.run(10);
        p.say();
        p.sayHi("Jack");
        p.say("Tom", 666);

    }
}

class Person {
    public int run() {
        System.out.println("我在run...");
        return 0;
    }

    public void run(int i) {
        System.out.println("我在run...<" + i + ">");
    }

    public void say() {
        System.out.println("我在say...");
    }

    public void sayHi(String name) {
        System.out.println("Hi," + name + ",你好");
    }

    public int say(String name, int i) {
        System.out.println(name + "----" + i);
        return 0;
    }

}

5.5.2.5 AspectJProxyFactory

该类支持使用编程的方式,用@AspectJ注解定义切面,不实现任何的接口,创建代理对象。

AspectJ是目前大家最常用的 起到集成AspectJSpring,也就是我们平时长谈的:自动代理模式。它整个代理的过程全部交给Spring内部去完成,无侵入。

Demo体验

@Aspect
class MyAspect {

  //会被解析、包装成一个advisor1对象
    @Pointcut("execution(* hello(..))")
    private void beforeAdd() {
    }

  //解析、包装成advisor2对象
    @Before("beforeAdd()")
    public void before1() {
        System.out.println("-----------before-----------");
    }

}

在上述切面类定义中我们定义了一个切面服务类aspect(采用注解@Aspect标注的),其对应了一个MethodBeforeAdvice,实际上是一个AspectJMethodBeforeAdvice,该Advice对应的是上面的before1()方法,还对应了一个Pointcut:是一个AspectJExpressionPointcut。 该Advisor的语义拦截所有的方法名为“hello”的方法在它之前执行MyAspect.before1()方法。

如果我们现在需要创建一个代理对象,其需要绑定的Advisor逻辑跟上面定义的切面类中定义的Advisor类似。则我们可以进行如下编程:

    public static void main(String[] args) {
        AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new HelloServiceImpl());
		// 注意:此处得MyAspect类上面的@Aspect注解必不可少
        proxyFactory.addAspect(MyAspect.class);
        //proxyFactory.setProxyTargetClass(true);//是否需要使用CGLIB代理
        HelloService proxy = proxyFactory.getProxy();
        proxy.hello();

        System.out.println(proxy.getClass()); //class com.sun.proxy.$Proxy6
    }
输出:
-----------before-----------
this is my method~~
class com.sun.proxy.$Proxy6

这里面很有意思的地方在于:我们只是proxyFactory.addAspect(MyAspect.class);,就自动帮我们完成了方法、通知的绑定工作。

注意:

  • 需要注意的是在使用AspectjProxyFactory基于切面类创建代理对象时,我们指定的切面类上必须包含@Aspect注解。
  • 虽然我们自己通过编程的方式可以通过AspectjProxyFactory创建基于@Aspect标注的切面类的代理,但是通过配置<aop:aspectj-autoproxy/>(@EnableAspectJAutoProxy)使用基于注解的Aspectj风格的Aop时,Spring内部不是通过AspectjProxyFactory创建的代理对象,而是通过ProxyFactory(这个在分析自动代理源码的时候有说到过~~~~)

5.5.2.6 ProxyFactory逻辑总结

AspectJProxyFactory,ProxyFactoryBean,ProxyFactory 大体逻辑都是:

  1. 填充AdvisedSupport(将代理对象target,注册的interceptorName,也就是advice增强名称,也就是将所有advice转换为advisor填充入advisedSupport),然后交给父类ProxyCreatorSupport
  2. 得到JDK或者CGLIB的AopProxy
  3. 代理调用时候被invoke或者intercept方法拦截 (分别在JdkDynamicAopProxyObjenesisCglibAopProxy(CglibAopProxy的子类)中) 并且在这两个方法中调用ProxyCreatorSupportgetInterceptorsAndDynamicInterceptionAdvice方法去初始化advice和各个方法直接映射关系并缓存

image-20230310115938173

该部分,是advised部分的整体逻辑。

5.5.3 ProxyProcessorSupport

为自动代理创建器AutoProxyCreator提供基础的方法,且其为proxyConfig配置类。

image-20230310120001503

该类为proxy processor处理器提供基本功能,包括classloader的管理和evaluateProxyInterfaces方法,该方法判断class上的接口,如果接口interfaces,则设置到proxyfactory中;如果没有接口,设置proxyFactory.setProxyTargetClass(true),表示用cglib创建代理类。

public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {
	/**
	 * This should run after all other processors, so that it can just add
	 * an advisor to existing proxies rather than double-proxy.
	 * 【AOP的自动代理创建器必须在所有的别的processors之后执行,以确保它可以代理到所有的小伙伴们,即使需要双重代理得那种】
	 */
	private int order = Ordered.LOWEST_PRECEDENCE;
	// 当然此处还是提供了方法,你可以自己set或者使用@Order来人为的改变这个顺序~~~
	public void setOrder(int order) {
		this.order = order;
	}
	@Override
	public int getOrder() {
		return this.order;
	}
	
	...
	// 这是它提供的一个最为核心的方法:这里决定了如果目标类没有实现接口直接就是Cglib代理
	// 检查给定beanClass上的接口们,并交给proxyFactory处理
	protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
		// 找到该类实现的所有接口们~~~
		Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
			
		// 标记:是否有存在【合理的】接口~~~
		boolean hasReasonableProxyInterface = false;
		for (Class<?> ifc : targetInterfaces) { //1
			if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
					// 如果所实现的接口,有一个接口有方法,就标识为,当前代理类beanclass有合理的代理接口
					ifc.getMethods().length > 0) { //2 
				hasReasonableProxyInterface = true;
				break;
			}//2 
		}	//1 
    
    //如果被代理类有合理的class接口
		if (hasReasonableProxyInterface) {
			// Must allow for introductions; can't just set interfaces to the target's interfaces only.
			// 这里Spring的Doc特别强调了:不能值只把合理的接口设置进去,而是都得加入进去
			for (Class<?> ifc : targetInterfaces) {
				proxyFactory.addInterface(ifc);
			}
		}
		else {
			// 这个很明显设置true,表示使用CGLIB得方式去创建代理了~~~~
			proxyFactory.setProxyTargetClass(true);
		}
	}

	// 判断此接口类型是否属于:容器去回调的类型,这里例举处理一些接口 初始化、销毁、自动刷新、自动关闭、Aware感知等等
	protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
		return (InitializingBean.class == ifc || DisposableBean.class == ifc || Closeable.class == ifc ||
				AutoCloseable.class == ifc || ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
	}
	// 是否是如下通用的接口。若实现的是这些接口也会排除,不认为它是实现了接口的类
	protected boolean isInternalLanguageInterface(Class<?> ifc) {
		return (ifc.getName().equals("groovy.lang.GroovyObject") ||
				ifc.getName().endsWith(".cglib.proxy.Factory") ||
				ifc.getName().endsWith(".bytebuddy.MockAccess"));
	}
}

类ProxyProcessorSupport作用,是对传入的beanClass和其proxyFactory参数,检查是否实现接口,如果有向proxyFactory设置接口;如果没有,设置代理模式为cglib。

5.5.3.1 AbstractAutoProxyCreator

image-20230310120032675

该类是对自动代理创建器的抽象实现,并且实现了[InstantiationAwareBeanPostProcessor](#3.3.3.1.1 InstantiationAwareBeanPostProcessor)接口,所以该类会介入springIOC容器实例化bean的前后调用,如果有需要返回的proxy代理对象,则终止常规默认的实例化。且因为其是BeanPostProcessor,会在初始化的前后被调用。

这里重点提一个方法(如下图):在bean被create之前,先会执行所有的InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,谁第一个返回了不为null的Bean,后面就都不会执行了 。然后会再执行BeanPostProcessor#postProcessAfterInitialization

img

AbstractAutoProxyCreator作用:

image-20230310120056909

整个Spring AOP模块的协作组件,它作为AOP的指挥官角色,统一协作Advisor(切面)和AopProxy(动态代理)这两大核心组件。它的本质是BeanPostProcessor(后置处理器)的一种实现,通过Spring IOC模块来启动运行。它针对的主体是Spring的Bean对象。

image-20230310120112673
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
     implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

     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 proxyFactory = new ProxyFactory();
          proxyFactory.copyFrom(this);

          if (!proxyFactory.isProxyTargetClass()) {
               if (shouldProxyTargetClass(beanClass, beanName)) {
                    proxyFactory.setProxyTargetClass(true);
               }
               else {
                    evaluateProxyInterfaces(beanClass, proxyFactory);
               }
          }
					
       		//构建advisor的chain链
          Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
       //设置proxyfactory的属性
       		//将advisors添加入proxyfactory内list<Advisor>
          proxyFactory.addAdvisors(advisors);
          proxyFactory.setTargetSource(targetSource);
          customizeProxyFactory(proxyFactory);

          proxyFactory.setFrozen(this.freezeProxy);
          if (advisorsPreFiltered()) {
               proxyFactory.setPreFiltered(true);
          }

  //AbstractAutoProxyCreator.createProxy---->proxyFactory.getProxy---->createAopProxy().getProxy
       //上述调用链,创建AOP的代理类
          return proxyFactory.getProxy(getProxyClassLoader());
     }

通过createProxy,创建proxyfactory,来获取AopProxy代理对象。

完成以下任务:

  1. 通过扫描有@Aspect注解的类,构建候选的Advisor切面集合;

  2. 在Aspect注解类中循环查找没有@PointCut注解的方法封装成Advice对象(@Aspect注解的类是切面类,其中包括两部分:@PointCut标注的部分,为切点定义;非@PointCut的方法,对应的就是增强方法,需要封装成Advice);

  3. 通过方法上的注解找到对应的PointCut拦截目标,并把Advisor上的表达式封装到PointCut对象中;

  4. 然后结合当前的Bean对象的元数据,过滤找到有效的Advisor集合。

  5. 最后通过beanClass创建针对当前bean的动态代理对象;在代理对象执行方法时,拦截方法,动态运行Advisor调用链,完成对当前bean中匹配目标的拦截和增强。

    image-20220419181559066

5.5.3.2 区别ProxyCreatorSupport和AbstractAutoProxyCreator

两个类是ProxyConfig的两大实现类,前者是ProxyFactory的父类,用来手动创建代理对象;后者继承自InstantiationAwarePostProcessor,会在bean实例化和初始换的前后,被调用,而且,该类内部在创建代理类createProxy时,是通过创建ProxyFactory,并调用ProxyFactory.getProxy方法创建代理对象的。

image-20230310120147824

5.5.3.3 AnnotationAwareAspectJAutoProxyCreator

image-20230310120205138

InstantiationAwareBeanPostProcessor作为后置处理器对象,但是其作为InstantiationAware,额外提供了bean实例化Instantiation的before和after的处理方法,如下:

image-20220422045910160

5.5.3.4 AopInfrastructureBean

image-20230310120220986

ProxyProcessorSupport是AopInfrastructureBean的实现类。

实现该接口,表示该bean是一个springaop的基础类,该类不会被aop代理,不会产生aop的代理对象,即使该bean被advisor切面所切入。

5.5.4 AopProxyFactory

aopProxy的factory工厂类,负责创建aopProxy

public interface AopProxyFactory {

	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

image-20220428123339031

5.5.4.1 DefaultAopProxyFactory

该类定义了createAopProxy的逻辑

//DefaultAopProxyFactory#createAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	
		// 需要对代理进行优化、代理的是目标类(强制cglib)、没有实现接口等都会进入这里面来
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { //1 
			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.");
			}
			// 倘若目标Class本身就是个接口,或者它已经是个JDK得代理类(Proxy的子类。所有的JDK代理类都是此类的子类),仍旧用JDK的动态代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// 实用CGLIB代理方式 ObjenesisCglibAopProxy是CglibAopProxy的子类。Spring4.0之后提供的
			return new ObjenesisCglibAopProxy(config);
		} //1 
    
		// 否则(一般都是有实现接口) 都会采用JDK得动态代理
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

	// 如果它没有实现过接口(ifcs.length == )  或者 仅仅实现了一个接口,但是呢这个接口却是SpringProxy类型的   那就返回false
	// 总体来说,就是看看这个cofnig有没有实现过靠谱的、可以用的接口
	// SpringProxy:一个标记接口。Spring AOP产生的所有的代理类 都是它的子类~~
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}
}

创建AopProxy的逻辑流程:

image-20220504234718978

5.5.4.2 AopProxy

AopProxy是独立的接口,不依赖于Proxy

image-20220428124236286

AopProxy是springAOP中特殊的自用的类。有两个不同实现类,来创建代理对象。

public interface AopProxy {

Object getProxy();

Object getProxy(@Nullable ClassLoader classLoader);

}

动态代理的基接口,它扩展了JDK内置的动态代理能力和Cglib类代理能力;

posted @ 2023-03-10 17:15  LeasonXue  阅读(346)  评论(0)    收藏  举报