Spring

Spring AOP之AopProxy代理对象

2019-09-26  本文已影响0人  九点半的马拉

在Spring的AOP模块,一个主要的部分是代理对象的生成,可以通过ProxyFactoryBean来完成,它封装了主要代理对象的生成过程。在这个生成过程中,可以使用JDK的Proxy和CGLIB两种生成情况。

JDK动态代理与CGLIB区别

  1. jdk动态代理是利用反射机制生成的一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
  2. CGLIB动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
  3. 如果目标对象实现了接口,默认情况下采用JDK的动态代理实现AOP,但可以强制性使用CGLIB实现AOP
  4. 如果目标对象没有实现接口,必须采用cglib库,

Tip: 什么是匿名类
即没有名称的类,其名称由Java编译器给出,一般为:外部类名称+$+匿名类顺序,名称也就是其他地方不能引用,不能实例化,只用一次,当然也就不能有构造器。

配置ProxyFactoryBean

  1. 定义通知器Advisor,这个通知器应该作为一个Bean来定义,定义了需要对目标对象进行增强的切面行为,也就是Advice通知。
  2. 定义ProxyFactoryBean,作为另一个Bean来定义,它是封装AOP功能的主要类。需要设定相关属性。

生成AopProxy代理对象

在ProxyFactoryBean中,需要为target目标对象生成Proxy代理对象,从而为AOP横切面的编织做好准备。从FactoryBean中获取对象,是以getObject()方法作为入口完成的。在该方法中,首先对通知器链进行初始化,封装了一系列的拦截器,这些拦截器都要从配置中读取,然后为代理对象的生成做好准备。在生成代理对象时,因为Spring中有singleton类型和prototype类型这两种不同的Bean,所以要对代理对象的生成做一个区分。

public Object getObject() throws BeansException {
        initializeAdvisorChain();
        if (isSingleton()) {
            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();
        }
    }

首先为Proxy代理对象配置Advisor链,在initializeAdvisorChain()方法中执行。
在该方法中它会首先通过this.advisorChainInitialized来判断通知器链是否已经初始化了,如果已经初始化了,就直接返回。其他情况下,通过this.interceptorNames来要添加的通知器名,然后通过该名从IOC容器中取得的通知器加入到拦截器链中。

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
        if (this.advisorChainInitialized) {
            return;
        }

        if (!ObjectUtils.isEmpty(this.interceptorNames)) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
            }

            // Globals can't be last unless we specified a targetSource using the property...
            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) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Configuring advisor or advice '" + name + "'");
                }

                if (name.endsWith(GLOBAL_SUFFIX)) {
                    if (!(this.beanFactory instanceof ListableBeanFactory)) {
                        throw new AopConfigException(
                                "Can only use global advisors or interceptors with a ListableBeanFactory");
                    }
                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
                }

                else {
                    // If we get here, we need to add a named interceptor.
                    // We must check if it's a singleton or prototype.
                    Object advice;
                    if (this.singleton || this.beanFactory.isSingleton(name)) {
                        // Add the real Advisor/Advice to the chain.
                        advice = this.beanFactory.getBean(name);
                    }
                    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);
                    }
                    addAdvisorOnChainCreation(advice, name);
                }
            }
        }

        this.advisorChainInitialized = true;
    }

生成singleton的代理对象在getSingletonInstance()中完成
如果它还没有被创建,则lazily creating

在Spring代理目标target时,其实并不是直接创建一个目标target的对象实例的,而是通过一个TargetSource类型的对象对目标target进行封装,Spring Aop获取目标对象始终是通过TargetSource.getTarget()方法进行的。

proxy(代理对象)代理的不是target,而是TargetSource

那么问题来了:为什么SpringAOP代理不直接代理target,而需要通过代理TargetSource(target的来源,其内部持有target),间接代理target呢?

通常情况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,可以扩展出很多高级功能,如:target pool(目标对象池)、hot swap(运行时目标对象热替换),等等。

Spring内置了多种TargetSource

在上面简单介绍了有关TargetSource的有关知识,接下来将对getSingletonInstance()方法的有关步骤进行解释。

private TargetSource freshTargetSource() {
   if (this.targetName == null) {
      if (logger.isTraceEnabled()) {
         logger.trace("Not refreshing target: Bean name not specified in 'interceptorNames'.");
  }
      return this.targetSource;
  }
   else {
      if (this.beanFactory == null) {
         throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
               "- cannot resolve target with name '" + this.targetName + "'");
  }
      if (logger.isDebugEnabled()) {
         logger.debug("Refreshing target with name '" + this.targetName + "'");
  }
      Object target = this.beanFactory.getBean(this.targetName);
 return (target instanceof TargetSource ? (TargetSource) target : new SingletonTargetSource(target));
  }
}
@Override @Nullable public Class<?> getTargetClass() {
   return this.targetSource.getTargetClass(); }
protected Object getProxy(AopProxy aopProxy) {
   return aopProxy.getProxy(this.proxyClassLoader); }
protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
  }
   return getAopProxyFactory().createAopProxy(this); }

监听调用AdvisedSupportListener实现类的activated方法

private void activate() {
   this.active = true;
 for (AdvisedSupportListener listener : this.listeners) {
      listener.activated(this);
  }
}

具体的代理对象的生成,是在ProxyFactoryBean的基类AdvisedSupport的实现中借助AopProxyFactory完成的,这个代理对象要么从JDK中生成,要么借助CGLIB获得。

这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactor。

如果targetClass是接口类,使用JDK来生成Proxy
如果不是接口类要生成Proxy,那么使用CGLIB来生成。

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.");
  }
      if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
         return new JdkDynamicAopProxy(config);
  }
      return new ObjenesisCglibAopProxy(config);
  }
   else {
      return new JdkDynamicAopProxy(config);
  }
}

接下来分别介绍两种不同的方式来产生AopProxy代理对象

  1. JdkDynamicAopProxy
@Override public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
  }
  # 获取AdvisedSupport类型对象的所有接口
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   # 接口是否定义了 equals和hashcode方法 正常是没有的
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); }

首先从advised对象中取得代理对象的代理接口配置,然后调用Proxy的newProxyInstance方法,得到最终的Proxy代理对象。

在生成代理对象时,需要指明三个参数,类加载器,代理接口和Proxy回调方法所在的对象。
在回调方法所在对象中,需要实现InvocationHandler接口,它定义了invoke方法,
对于JdkDynamimcAopProxy,它本身实现了InvocationHandler接口和invoke方法,这个invoke方法是Proxy代理对象的回调方法。

  1. CGLIB生成代理对象

在该篇文章中就不讲解了,感兴趣的可以百度搜索。

注:本文大多数是对《Spring技术内幕》的阅读整理。

上一篇 下一篇

猜你喜欢

热点阅读