AOP(Aspect-OrientedProgramming,面向方面编程)是OOP(Object-Oriented Programing,面向对象编程)的良好补充与完善,后者侧重于解决

从上到下的存在明显层次逻辑关系的问题,而前者则侧重于由左至右的水平散布的无明显逻辑关系但具备相同行为的问题。AOP抽象的是相同的行为而非

关联的行为,用于提供通用服务支持,而非业务逻辑处理,其核心思想是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。

AOP植入有多种不同方式,主要分为以下三种方式:

  1. 编译期植入
  2. 类装载期植入
  3. 动态代理植入

Spring中AOP具体的配置过程,可通过以下途径:

  1. 配置ProxyFactoryBean,显式设置advisors, advice, target等
  2. 配置AutoProxyCreator,使用定义bean的方式不变,但是从容器中获得的是代理对象

最顶层是ProxyConfig是一个数据,这个数据基类为ProxyFactoryBean这样的子类提供了配置属性;

AdvisedSupport的封装了Aop对通知和通知器的相关操作,这些操作对于不同的Aop的代理对象的生成都是一样的,

但对于具体的Aop代理对象的创建,AdvisedSupport把它交给它的子类们去完成;对于ProxyCreatorSupport,

可以将它看成是其子类创建Aop代理对象的一个辅助类;具体的Aop代理对象的生成,根据不同的需要,

分别由ProxyFactoryBean、ProxyFactory、AspectJProxyFactory来完成

AbstractAutoProxyCreator 实现了BeanPostProcessor,当系统比较复杂或者中需要进行aop织入的bean较多时,

简单采用ProxyFacotryBean无疑会增加很多工作量,同时由于要从ProxyFactoryBean获得代理对象,也会使应用

和Spring之间的耦合度增加,这样的情况下,自动Aop代理的方式就能发挥它巨大的优势了。

一、AOP对象的生成

1.ProxyFactory是怎样得到代理类的

public Object getProxy() {
return createAopProxy().getProxy();
} protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}

2.ProxyFactoryBean是怎样获得代理类的

ProxyFactoryBean是在Spring IoC环境中。

    @Override
public Object getObject() throws BeansException {
initializeAdvisorChain(); //初始化通知器
if (isSingleton()) {
return getSingletonInstance();//依据定义生成单例的Proxy
}
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(); //这里依据定义生成prototype的Proxy
}
}

使用示例

public class SayMehthodInterceptor implements MethodInterceptor {

    @Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println(" method对象:" + invocation.getMethod() );
System.out.println(" invocation对象:" + invocation);
return invocation.proceed();
}
} public static void proxyFactoryBean(){
ProxyFactoryBean factory = new ProxyFactoryBean(); //给代理工厂一个原型对象
factory.setTarget(new Person()); factory.addAdvisors(getAdvisor()); //从代理工厂中获取一个代理后的对象
Person p = (Person) factory.getObject();
p.say();
} public static void proxyFactory(){
ProxyFactory factory = new ProxyFactory();
factory.setTarget(new Person());
factory.addAdvisors(getAdvisor()); Person p = (Person) factory.getProxy();
p.say();
} private static Advisor getAdvisor(){
//切点
JdkRegexpMethodPointcut cut = new JdkRegexpMethodPointcut();
cut.setPatterns(new String[]{".*run.*",".*say.*"});//可以配置多个正则表达式 //通知
//Advice advice = new SayMehthodInterceptor();
Advice advice = new CarLinkServiceInterceptor(); //切面 = 切点 + 通知
return new DefaultPointcutAdvisor(cut, advice); }

二、实现类比较

1. ProxyFactoryBean

使用率最高的 proxy 方式, 它通过配置 interceptorNames 属性决定加入哪些 advisor (method interceptor 将会被自动包装成 advisor, 下文将描述这个细节), 
注意是 "interceptorNames" 而不是 "interceptors",

原因是 ProxyFactoryBean 可能返回非 singleton 的 proxy 实例, 而 advisior 可能也是非 singleton 的,

因此不能通过 interceptor reference 来注入

2. TransactionProxyFactoryBean

特定用于 transaction proxy, 注意其 super class 是 AbstractSingletonProxyFactoryBean, 也就是说,

TransactionProxyFactoryBean 永远无法返回非 singleton 的 proxy 实例

如果你需要非 singleton 的 proxy 实例, 请考虑使用 ProxyFactoryBean.

3. BeanNameAutoProxyCreator

故名思义, 根据 bean name 进行 auto proxy, bean name 的 match 规则参见 org.springframework.util.PatternMatchUtils

4. DefaultAdvisorAutoProxyCreator

更强大的 auto proxy creator, 强大之处在于它会 cahce 容器中所有注册的 advisor, 然后搜索容器中所有的 bean , 
如果某个 bean 满足 advisor 中的 Pointcut, 那么将会被自动代理, 与 BeanNameAutoProxyCreator 相比, 省去了配置 beanNames 的工作

5.InfrastructureAdvisorAutoProxyCreator

只解析spring 自身的 advisor, 用户自定义的不处理

三、org.aopalliance.intercept.MethodInterceptor 如何被包装成 Advisor

    /**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
} @Override
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}

从代码可以看到, 如果 adviceObject(也就是 interceptorNames 对应的 bean) 不是 advisor

而是 MethodInterceptor 或 Advice, 那么 spring 将其包装成 DefaultPointcutAdvisor,

而 DefaultPointcutAdvisor 中定义的 Pointcut 是 TruePointcut .

也就是说, MethodInterceptor 和 Advice 被包装成的 Advisor 将会匹配容器中的所有 bean,

所以, 永远不要在 DefaultAdvisorAutoProxyCreator 的 interceptorNames 中引用一个 Advice,

那将会使容器中所有的 bean 被自动代理!!! 此时应该考虑使用 BeanNameAutoProxyCreator

参考:

网易乐得技术团队:Spring-SpringMVC父子容器&AOP使用总结

spring aop 代理对象生成

AOP代理对象生成的更多相关文章

  1. 深入理解Spring AOP之二代理对象生成

    深入理解Spring AOP之二代理对象生成 spring代理对象 上一篇博客中讲到了Spring的一些基本概念和初步讲了实现方法,当中提到了动态代理技术,包含JDK动态代理技术和Cglib动态代理 ...

  2. Spring进阶之路(10)-Advice简单介绍以及通过cglib生成AOP代理对象

    Advice简单介绍 1. Before:在目标方法运行之前运行织入.假设Before的处理中没有进行特殊的处理.那么目标方法终于会运行,可是假设想要阻止目标方法运行时.能够通过抛出一个异常来实现.B ...

  3. spring5 源码深度解析----- AOP代理的生成

    在获取了所有对应bean的增强后,便可以进行代理的创建了.回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下所示: protected static fi ...

  4. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  5. AOP之proceedingjoinpoint和joinpoint区别(获取各对象备忘)、动态代理机制及获取原理代理对象、获取Mybatis Mapper接口原始对象

    现在AOP的场景越来越多,所以我们有必要理解下和AOP相关的一些概念和机制. import org.aspectj.lang.reflect.SourceLocation; public interf ...

  6. Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理

    AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...

  7. 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  8. Springboot源码分析之代理对象内嵌调用

    摘要: 关于这个话题可能最多的是@Async和@Transactional一起混用,我先解释一下什么是代理对象内嵌调用,指的是一个代理方法调用了同类的另一个代理方法.首先在这儿我要声明事务直接的嵌套调 ...

  9. Spring Aop(十二)——编程式的创建Aop代理之AspectjProxyFactory

    转发地址:https://www.iteye.com/blog/elim-2397922 编程式的创建Aop代理之AspectjProxyFactory 之前已经介绍了一款编程式的创建Aop代理的工厂 ...

随机推荐

  1. 【原创】大叔经验分享(20)spark job之间会停顿几分钟

    今天遇到一个问题,spark应用中在一个循环里执行sql,每个sql都会向一张表写入数据,比如 insert overwrite table test_table partition(dt) sele ...

  2. uboot、内核、根文件系统启动流程

    [1]Uboot的启动流程  Uboot的启动分为两个阶段.  第一阶段:设置异常向量表,设置ARM核为svc模式,关cache和关mmu,  关看门狗,初始化时钟,串口,内存,初始化栈空间,清bss ...

  3. jq-css、class、属性操作

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. JAVA 动态代理原理和实现

    在 Java 中动态代理和代理都很常见,几乎是所有主流框架都用到过的知识.在面试中也是经常被提到的话题,于是便总结了本文. Java动态代理的基本原理为:被代理对象需要实现某个接口(这是前提),代理对 ...

  5. hexo基本操作

    1.新建一篇文章:hexo new post "article title" 2.生成静态网页:hexo g 3.预览效果:hexo s 4.发布:hexo d

  6. thinkphp5图片上传接口

    public function avatarUpload() { $file = request()->file('file'); $filePath = 'avatar'; $width = ...

  7. mybatis 开发规范

  8. [转自大神]js拖拽小总结

    https://blog.csdn.net/u013040887/article/details/83059094 权侵删 这里写的是一个原生js实现拖拽的效果,首先: 1.实现拖拽的三大事件,是要首 ...

  9. GCD Counting-树形DP

    GCD Counting 思路: 预处理  每个权值的素因子.问题转化为  以同一个素数作为因子 最长的链, 树形DP求解,ans 由 此点的 最长子链 + 次长子链 相加得到, 然后再更新最长子链 ...

  10. Python垃圾回收机制--完美讲解!

    转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...