前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring aop 的代理机制

Spring aop 的代理机制

作者头像
java达人
发布2018-01-31 18:43:56
6280
发布2018-01-31 18:43:56
举报
文章被收录于专栏:java达人

Spring aop 是通过代理实现的,代理有静态代理,jdk动态代理和cglib动态代理,代理就像我们生活中的房产中介,你不直接与房主,银行接触,而是通过中介与他们沟通联系。

代理的结构如图所示:

RealSubject 和 Proxy都实现了相同的接口Subject,Proxy持有RealSubject的引用,但Client 调用 request方法时,Proxy将请求转发给RealSubject,其中可以添加各种访问控制。

但是静态代理有一个弊端,需要为每一个目标类创建一个代理类,如果需要代理的对象很多的话,就得编写相应的代理类,于是jdk动态代理出现了,它主要用了 java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

我们先实现java.lang.reflect.InvocationHandler,添加需要的横切逻辑

代码语言:js
复制
public class AccessControl implements InvocationHandler {
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用前的处理
  System.out.println("调用前验证");
  Object obj  = method.invoke(proxy, args);
//调用后的处理
  System.out.println("调用后处理");
 return obj;
 }

}

然后通过Proxy为不同的类型生成相应的代理对象。

Proxy.newProxyInstance(targertClass1.getClassLoader(), targertClass1.getInterfaces(),accessControl);

Proxy.newProxyInstance(targertClass2.getClassLoader(), targertClass2.getInterfaces(),accessControl);

不管targetClass有多少类型,都可以通过Proxy生成具有相同访问控制accesControl的代理对象。

从上面示例可知jdk动态代理需要被代理类实现接口(Interface),对于没有实现任何接口的目标对象,我们就要另找方法了。默认情况下,当Spring发现目标对象没有实现任何接口时,会使用CGLIB,为目标对象动态生成代理对象,其实质就是对目标对象进行继承,生成子类,子类覆盖父类的方法,在其中加入额外的访问控制,不过如果类中的方法声明为final的话,就不能对它进行扩展。

Spring 创建代理的秘密在DefaultAopProxyFactory 类中可以找到:

代码语言:js
复制
 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()) {
 return new JdkDynamicAopProxy(config);
   }
 return CglibProxyFactory.createCglibProxy(config);
  } else {
 return new JdkDynamicAopProxy(config);
  }
 }

如果isOptimize()返回true,或者proxyTargetClass属性为true,或者目标对象没有接口实现,就采用cglib动态代理,否则就用jdk动态代理。再看看JdkDynamicAopProxy中的getProxy

代码语言:js
复制
public Object getProxy(ClassLoader classLoader) {
 if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
  }
  Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
  findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
 }

请看最后一行代码,是否有似曾相识之感。

Spring aop 仅作用于方法,如果你想对构造方法或字段作拦截处理,就要引入AspectJ,它支持在编译期间织入横切逻辑,提高运行期间的性能,但在易用性和灵活性上不如Spring aop。值得注意的是,Spring中@AspectJ注解区别的切面也是基于Spring aop 的代理机制实现的,不要被这个名称混淆了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-07-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档