Spring AOP代理对象创建时机

Posted qq_41084438

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring AOP代理对象创建时机相关的知识,希望对你有一定的参考价值。

1、AOP代理对象创建的时机

public class 代理对象 

    private 普通对象类型 普通对象;

    
    public Object proxyMethod(...) 
        
        do something
        普通对象.method(xxx)
        do something
    
 

AOP的原理可以简单这么认为,代理对象持有被代理对象(因为代理对象的字段并不会被赋值,都是null,所以需要用到被代理对象字段的值),通过在调用被代理对象方法前后做一些事情。

在Spring中,我们经常会为我们的Bean做AOP,根据上面我们知道,代理对象需要引用被代理对象,那就需要在Bean初始化完成之后再对Bean做代理。因为Bean初始化完成之后就是一个可用的Bean了,而且会被放入IOC容器,我们需要在这个Bean被放入IOC容器之前生成它的代理对象,并代替原先的类放入IOC容器中。

 这是一个Bean的生命周期流程,当它执行完第六步,也就是初始化方法执行完毕之后,这个Bean就可用了。而第七步是Spring给我们提供的扩展点,在这一步可以拿到可用的原始对象,我们的代理对象生成和替换就是在这里。

public interface BeanPostProcessor 


	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException 
		return bean;
	


	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException 
		return bean;
	


位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

 位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

 从源码可以知道,Spring在调用BeanPostProcessor的postProcessAfterInitialization方法会传入原始对象,并把postProcessAfterInitialization方法返回的对象替换原始对象,所以我们只要在postProcessAfterInitialization方法实现代理对象的生成逻辑即可。

2、实现

我用的是JDK动态代理,所以需要被代理的对象去实现一个接口。

public interface TestInterface 

    void test();

然后被代理类通过依赖注入注入另一个类,去调用该类的一个方法。验证被代理类被代理前已经可用。

@Service
public class OtherTestService 

    public void test() 
        System.out.println("OtherTestService test()");
    

被代理类

@Service
public class TestImpl implements TestInterface 

    @Autowired
    private OtherTestService otherTestService;

    @Override
    public void test() 
        otherTestService.test();
    

生成代理类



@Component
public class TestBeanPostProcess implements BeanPostProcessor 

    public Object postProcessAfterInitialization(Object bean, String beanName) throws
            BeansException 

        // 只代理testImpl这个bean 其他的不代理
        if (!beanName.equals("testImpl")) 
             return bean;
        

        return Proxy.newProxyInstance(TestBeanPostProcess.class.getClassLoader(),
                bean.getClass().getInterfaces(), new InvocationHandler() 
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable 
                        System.out.println("代理前");
                        Object invoke = method.invoke(bean, args);
                        System.out.println("代理后");
                        return invoke;
                    
                );
    

3、Test

@SpringBootApplication
public class AopDemoApplication 

    public static void main(String[] args) 
        ConfigurableApplicationContext run = SpringApplication.run(AopDemoApplication.class, args);
        TestInterface testImpl = (TestInterface) run.getBean("testImpl");
        testImpl.test();
    

demo 代码:https://download.csdn.net/download/qq_41084438/87620267

Spring读源码系列之AOP--04---proxyFactory创建代理对象

Spring读源码系列之AOP--04---proxyFactory创建代理对象


引言

Spring作为一个优秀的框架,提供了多种应用层面上代理的方式:ProxyFactoryBean、ProxyFactory、AspectJProxyFactory

注意:此处这里指的是Spring提供的应用层得方式,并不是指的底层实现方式。底层实现方式现在只有业界都熟悉的两种:JDK动态代理和CGLIB代理~

ProxyFactoryBean是将我们的AOP和IOC融合起来,而ProxyFactory 则是只能通过代码硬编码进行编写 一般都是给spring自己使用。而AspectJ是目前大家最常用的集成AspectJ和Spring~~~


Spring AOP进化史:

阅读本文前,请先弄清楚aop底层各个组件的作用和之间的关系,具体参考下文:

Spring读源码系列之AOP–03—aop底层基础类学习


ProxyCreatorSupport—代理对象创建支持

代理工厂的基类。提供对可配置 AopProxyFactory 的便捷访问。

public class ProxyCreatorSupport extends AdvisedSupport 
    //负责生产代理对象的工厂
	private AopProxyFactory aopProxyFactory;
   //监听器
	private final List<AdvisedSupportListener> listeners = new ArrayList<>();

	/** Set to true when the first AOP proxy has been created. */
	private boolean active = false;

	public ProxyCreatorSupport() 
		this.aopProxyFactory = new DefaultAopProxyFactory();
	

	public ProxyCreatorSupport(AopProxyFactory aopProxyFactory) 
		Assert.notNull(aopProxyFactory, "AopProxyFactory must not be null");
		this.aopProxyFactory = aopProxyFactory;
	


	public void setAopProxyFactory(AopProxyFactory aopProxyFactory) 
		Assert.notNull(aopProxyFactory, "AopProxyFactory must not be null");
		this.aopProxyFactory = aopProxyFactory;
	
	
	public AopProxyFactory getAopProxyFactory() 
		return this.aopProxyFactory;
	


	public void addListener(AdvisedSupportListener listener) 
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.add(listener);
	

	public void removeListener(AdvisedSupportListener listener) 
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.remove(listener);
	


	/**
子类应该调用它来获得一个新的 AOP 代理。他们不应该以 this 作为参数来创建 AOP 代理。
	 */
	protected final synchronized AopProxy createAopProxy() 
		if (!this.active) 
			activate();
		
		return getAopProxyFactory().createAopProxy(this);
	

	/**
	 * Activate this proxy configuration.
	 * @see AdvisedSupportListener#activated
	 */
	private void activate() 
		this.active = true;
		for (AdvisedSupportListener listener : this.listeners) 
			listener.activated(this);
		
	

	/**
	 * Propagate advice change event to all AdvisedSupportListeners.
	 * @see AdvisedSupportListener#adviceChanged
	 */
	@Override
	protected void adviceChanged() 
		super.adviceChanged();
		synchronized (this) 
			if (this.active) 
				for (AdvisedSupportListener listener : this.listeners) 
					listener.adviceChanged(this);
				
			
		
	

	/**
	 * Subclasses can call this to check whether any AOP proxies have been created yet.
	 */
	protected final synchronized boolean isActive() 
		return this.active;
	



主要就是通过createAopProxy方法来创建一个代理对象


AopProxyFactory—生产AopProxy的工厂

由能够基于 AdvisedSupport 配置对象创建 AOP 代理的工厂实现的接口。

Proxies 应该遵守下面的约定:

  • 他们应该实现配置指示应该被代理的所有接口。
  • 他们应该实现 Advised 接口.
  • 他们应该实现 equals 方法来比较代理接口、advice和目标对象。
  • 如果所有advisors和目标对象都是可序列化的,它们应该是可序列化的。
  • 如果advisors和目标是线程安全的,它们应该是线程安全的。

代理可能允许也可能不允许更改advice。如果它们不允许更改advice(例如,因为配置被冻结),代理应该在尝试更改建议时抛出 AopConfigException。

public interface AopProxyFactory 

	/**
	 * Create an  AopProxy for the given AOP configuration.
	 */
	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;



DefaultAopProxyFactory—选择是使用cglib还是jdk动态代理来创建代理对象

默认 AopProxyFactory 实现,创建 CGLIB 代理或 JDK 动态代理。

如果给定的 AdvisedSupport 实例满足以下条件之一,则创建 CGLIB 代理:

  • the optimize flag is
  • the proxyTargetClass flag is set
  • no proxy interfaces have been specified

通常,指定 proxyTargetClass 以强制执行 CGLIB 代理,或指定一个或多个接口以使用 JDK 动态代理。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable 


	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException 
		if (!NativeDetector.inNativeImage() &&
		//满足下面三个条件其中一个,则采用cglib代理
				(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 
		//采用jdk动态代理
			return new JdkDynamicAopProxy(config);
		
	

	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) 
	//通过AdvisedSupport拿到当前代理对象需要实现的接口,如果没有需要实现的接口或者需要实现的接口只有一个并且这个接口继承至 SpringProxy
	//返回true
		Class<?>[] ifcs = config.getProxiedInterfaces();
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	




ProxyFactoryBean----与IOC结合使用来创建代理类

FactoryBean 实现,它基于 Spring BeanFactory 中的 bean 构建 AOP 代理。

FactoryBean是spring中提供通过bean工厂的方式来向spring中注入bean,一般用于复杂bean的构建

ProxyFactoryBean维护了一个interceptorNames数组,该数组存放了所有应用于当前代理对象的拦截器,在旧版spring实现的,该数组最后一个元素是目标 bean 的名称或 TargetSource;但是,通常最好改用“targetName”“target”“targetSource”属性。

因为我们知道拦截器链中的拦截器全部调用完成后,会去调用目标方法,因此在spring中是将拦截器名称数组最后一个设置为了目标对象

返回的代理对象都可以转换为Advised,我们还可以脱离IOC单独使用ProxyFactory,通过编码方式来构建。

public class ProxyFactoryBean extends ProxyCreatorSupport
		implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware 

	/**
	 * This suffix in a value in an interceptor list indicates to expand globals.
	 * 如果拦截器名称以*结尾,说明是全局拦截器,需要去当前IOC和父容器中搜索获得
	 */
	public static final String GLOBAL_SUFFIX = "*";


	protected final Log logger = LogFactory.getLog(getClass());
    
    //存放应用到当前代理对象的拦截器名称数组
	@Nullable
	private String[] interceptorNames;
    //目标对象名称
	@Nullable
	private String targetName;
   //自动探测接口,默认开启--即可以自行选择使用jdk还是cglib动态代理
	private boolean autodetectInterfaces = true;
   //生成的代理对象是单例的还是多例的
	private boolean singleton = true;
  //获取全局共享的AdvisorAdapterRegistry,负责进行相关适配工作
	private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
   //是否冻结代理对象的相关配置
	private boolean freezeProxy = false;
  //加载代理对象的加载器
	@Nullable
	private transient ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
//加载器是否被手动配置了
	private transient boolean classLoaderConfigured = false;
//拿到IOC容器
	@Nullable
	private transient BeanFactory beanFactory;
//拦截器链是否完成了初始化
	private boolean advisorChainInitialized = false;
//如果生成的代理对象是单例的,那么该属性就用来缓存该生产的代理类单例对象
	@Nullable
	private Object singletonInstance;


	/**
手动指定代理类需要实现的接口,如果没指定,则使用cglib进行代理
但是因为默认开启了自动接口探测功能,所以这里一般不需要手动指定
	 */
	public void setProxyInterfaces(Class<?>[] proxyInterfaces) throws ClassNotFoundException 
	//设置到父类AdvisedSupport的interfaces接口集合中
		setInterfaces(proxyInterfaces);
	

	/**
设置当前代理对象关联的一组拦截器名称数组
	 */
	public void setInterceptorNames(String... interceptorNames) 
		this.interceptorNames = interceptorNames;
	

	/**
目标对象名字
	 */
	public void setTargetName(String targetName) 
		this.targetName = targetName;
	

	/**
对自动探测功能进行设置
	 */
	public void setAutodetectInterfaces(boolean autodetectInterfaces) 
		this.autodetectInterfaces = autodetectInterfaces;
	

	/**
	 * Set the value of the singleton property. Governs whether this factory
	 * should always return the same proxy instance (which implies the same target)
	 * or whether it should return a new prototype instance, which implies that
	 * the target and interceptors may be new instances also, if they are obtained
	 * from prototype bean definitions. This allows for fine control of
	 * independence/uniqueness in the object graph.
	 * 设置当前FactoryBean生产的代理对象是单例的还是多例的
	 */
	public void setSingleton(boolean singleton) 
		this.singleton = singleton;
	


	public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) 
		this.advisorAdapterRegistry = advisorAdapterRegistry;
	

	@Override
	public void setFrozen(boolean frozen) 
		this.freezeProxy = frozen;
	

	public void setProxyClassLoader(@Nullable ClassLoader classLoader) 
		this.proxyClassLoader = classLoader;
		this.classLoaderConfigured = (classLoader != null);
	

//默认proxyClassLoader 是BeanClassLoader
//该方法因为继承了BeanClassLoaderAware
	@Override
	public void setBeanClassLoader(ClassLoader classLoader) 
		if (!this.classLoaderConfigured) 
			this.proxyClassLoader = classLoader;
		
	

//该方法继承至BeanFactoryAware 
	@Override
	public void setBeanFactory(BeanFactory beanFactory) 
		this.beanFactory = beanFactory;
		checkInterceptorNames();
	


	/**
该方法继承至FactoryBean
	 */
	@Override
	@Nullable
	public Object getObject() throws BeansException 
	//初始化拦截器链
		initializeAdvisorChain();
		//判断是单例还是多例,分别处理
		if (isSingleton()) 
		//单例
			return getSingletonInstance();
		
		else 
			if (this.targetName == null) 
				logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			
			//多例
			return newPrototypeInstance();
		
	

	/**
继承FactoryBean的方法,返回创建对象的类型。将检查单例实例是否已创建,否则回退到代理接口(如果只有一个)、目标 bean 类型或 TargetSource 的目标类。
	 */
	@Override
	public Class<?> getObjectType() 
		synchronized (this) 
		//singletonInstance 缓存已经创建过的单例代理对象---单例在当前工厂内部会进行缓存,通过singletonInstance完成
			if (this.singletonInstance != null) 
				return this.singletonInstance.getClass();
			
		
		//如果代理对象需要实现的接口只有一个,那么返回的代理对象类型就为这个接口
		Class<?>[] ifcs = getProxiedInterfaces();
		if (ifcs.length == 1) 
			return ifcs[0];
		
		//如果需要实现的接口大于一个,那么会创建一个代理类实现这些接口,返回这个代理类的类型作为代理对象的类型
		else if (ifcs.length > 1) 
			return createCompositeInterface(ifcs);
		
		//尝试从IOC中获取bean的类型
		else if (this.targetName != null && this.beanFactory != null) 
			return this.beanFactory.getType(this.targetName);
		
		else 
	     //返回目标对象的类型
			return getTargetClass();
		
	

//继承至FctoryBean的方法,表示当前生产的对象是否是单例的
	@Override
	public boolean isSingleton() 
		return this.singleton;
	


	/**
	 * Create a composite interface Class for the given interfaces,
	 * implementing the given interfaces in one single Class.
	 * The default implementation builds a JDK proxy class for the
	 * given interfaces.
	 */
	protected Class<?> createCompositeInterface(Class<?>[] interfaces) 
	//通过jdk动态代理创建一个代理类继承传入的接口,然后返回代理类类型
		return ClassUtils.createCompositeInterface(interfaces, this.proxyClassLoader);
	

	/**
	 * Return the singleton instance of this class's proxy object,
	 * lazily creating it if it hasn't been created already.
	 * 获取类型为单例的代理对象
	 */
	private synchronized Object getSingletonInstance() 
	//singletonInstance不为空,说明单例对象已经创建过并且被缓存起来了
		if (this.singletonInstance == null) 
		//父类AdvisedSupport中维护了一个targetSource 属性---targetSource负责包装目标对象
		//从容器中找到targetName对应的bean,然后包装为TargetSource后返回
			this.targetSource = freshTargetSource();
		//开启了接口自动探测并且当前类没有实现任何接口并且没有设置ProxyTargetClass为true
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) 
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				//获取目标类的class
				Class<?> targetClass = getTargetClass();
				if (targetClass == null) 
					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
				
				//getAllInterfacesForClass这里会返回当前类继承和父类实现的所有接口
				//这里已经确定了当前类没有实现任何接口--那么这里判断的是当前targetClass为一个接口的时候
			   //会将目标类实现的接口放入父类advisedSupport的interfaces集合中,代表代理类需要实现的接口
			   //这里setInterfaces会将探测到的接口放入父类AdvisedSupport的interfaces接口集合中
			   //然后最后选择cglib还是jdk动态代理是需要对这个interfaces是否存在元素进行判断
				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			
			// Initialize the shared singleton instance.
			//锁住代理类的相关配置,不让其被修改
			super.setFrozen(this.freezeProxy);
			//获取代理对象---createAopProxy()通过DefaultAopProxyFactory创建代理对象--返回的是AopProxy
			//getProxy()获取到AopProxy包裹的代理对象
			this.singletonInstance = getProxy(createAopProxy());
		
		return this.singletonInstance;
	

	/**
   代理对象是多例:除了每次创建的代理对象都单独创建一个配置实例外并且没有singletonInstance 缓存外,其余和单例一致
	 */
	private synchronized Object newPrototypeInstance() 
		// In the case of a prototype, we need to give the proxy
		// an independent instance of the configuration.
		//在原型的情况下,我们需要给代理一个独立的配置实例。
		// In this case, no proxy will have an instance of this object's configuration,
		// but will have an independent copy.
		//在这种情况下,没有代理将拥有此对象配置的实例,但会有独立的副本。
		//即每次获取的代理对象都分配一个新的配置实例
		ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());

		// The copy needs a fresh advisor chain, and a fresh TargetSource.
		TargetSource targetSource = freshTargetSource();
		// freshAdvisorChain()刷新AdvisorChain主要是将PrototypePlaceholderAdvisor中的PrototypeAdvisorName获取到
		//并且从容器中取得对应的实例,然后加上一些共享的Advisor一起放入集合并返回
		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);

		return getProxy(copy.createAopProxy());
	

	/**
	 * Return the proxy object to expose.
	 * 获取aopProxy内部包裹的代理对象实例
	 */
	protected Object getProxy(AopProxy aopProxy) 

以上是关于Spring AOP代理对象创建时机的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP源码剖析

Spring AOP源码剖析

Spring AOP之AopProxy代理对象

Java——面向切面编程,Spring中的AOP编程

JAVA 框架-Spring-AOP面向切面

重温Spring之AOP