Introductions(引用),在 Aspect 中称为类型间的声明,使切面能够声明被通知的对象(拦截的对象)实现给定的接口,并提供该接口的实现。

  简单点说可以将一个类的实现方法复制到未实现的类中,动态的扩展类没有的方法。

  通过 @DeclareParents 注解进行声明,声明在一个父类型的属性上(比如接口),其中注解的属性 value 指定对哪些路径(包)下的类进行类方法扩展,defaultImpl 指定以哪个类为模板。

  如下案例:

  1)切面类:

@Aspect
@Component
public class LogAspects {@DeclareParents(value = "com.hrh.aop.*", defaultImpl = IndexDao.class)public static Dao dao;@Pointcut("execution(public * com.hrh.aop.*.*(..))")public void pointcut() {}@Before("pointcut()")public void LogStart() {System.out.println("LogStart...");}
}

  2)接口和实现类:

public interface Dao{void query();
}@Repository
public class IndexDao implements Dao{public void query(){System.out.println("query:"+this.getClass().getSimpleName());}
}

  3)配置类:

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.hrh.aop")
public class Config {
}

  4)空类:

@Repository("orderDao")
public class OrderDao{}

  5)测试和结果:

    public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);Dao bean = (Dao) context.getBean("indexDao");bean.query();System.out.println("----------");Dao dao = (Dao) context.getBean("orderDao");dao.query();}=========结果==========LogStart...query:IndexDao----------query:IndexDao

  根据前文Spring笔记(3) - SpringAOP基础详解和源码探究可以得知如下:

  • @EnableAspectJAutoProxy(proxyTargetClass=false),表示使用JDK动态代理(默认);
  • @EnableAspectJAutoProxy(proxyTargetClass=true),表示使用CGLIB代理;

  debug运行后查看beanFactory的OrderDao和IndexDao代理后的对象,如下图:

  从上面可以看到IndexDao的对象是使用JDK代理的,而OrderDao的对象是CGLIB代理的。

  那么当设置@EnableAspectJAutoProxy(proxyTargetClass=true)时,是如下图:

  由此可以判定@DeclareParents注解给拦截到的类进行代理使用的是CGLIB代理(其实OrderDao没有实现任何接口,所以最终实现的是CGLIB),那么可以查看下代理类生成的内容是什么,可以在context前面加一行代码将代理类class文件存入本地磁盘:

        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "xxx");//xxx是存放代理类class的本地路径AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

  下面是代理类class反编译后的完整代码(感兴趣可以完全打开,完全的很多内容,包含了各种父类的方法,比如toString、clone、equals、hashCode):

View Code【完整代码查看https://www.cnblogs.com/huangrenhui/p/14655795.html】

  从上面可以看到代理类里面有query方法,代理类继承了OrderDao和实现了Dao接口:

public class OrderDao$$EnhancerBySpringCGLIB$$ee33136 extends OrderDao implements Dao, SpringProxy, Advised, Factory {    ............................final void CGLIB$query$4() {super.query();}public final void query() {try {MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if (this.CGLIB$CALLBACK_0 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}if (var10000 != null) {var10000.intercept(this, CGLIB$query$4$Method, CGLIB$emptyArgs, CGLIB$query$4$Proxy);} else {super.query();}} catch (Error | RuntimeException var1) {throw var1;} catch (Throwable var2) {throw new UndeclaredThrowableException(var2);}}............................
}    

  从前文Spring笔记(3) - SpringAOP基础详解和源码探究可以得知在 AbstractAutoProxyCreator#wrapIfNecessary()中会对bean进行包装增强(代理),下面打下断点debug跟踪下流程:

  当执行到wrapIfNecessary方法下面的代码时,bean还是原对象(未被代理):

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

  当上面的代码执行完后,可以看到specificInterceptors数组包含了advice(通知)、introducedInterface(引用接口)、typePatternClassFilter(class过滤规则,重点),其中advice包含了defaultImplType(默认实现类型,上面代码中定义的),可以看到是IndexDao,interfaceType(接口类型)可以看到是Dao,以上信息是通过解析@DeclareParents注解而来的:

  下面typePatternClassFilter里面的详情,可以看到,上面的信息又包含在typePatternClassFilter里面,同时里面包含了过滤规则:

  最后通过DefaultAopProxyFactory#createAopProxy方法创建的对象如下图:

  当执行query方法时,CglibAopProxy.DynamicAdvisedInterceptor#intercept方法进行拦截时,会执行父类的方法ReflectiveMethodInvocation#ReflectiveMethodInvocation:

  执行完会跳转到ReflectiveMethodInvocation#proceed执行方法的执行:

    public Object proceed() throws Throwable {// We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}//获取通知Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);//执行方法}}    

  下面执行delegate对象获取到IndexDao,然后AopUtils.invokeJoinpointUsingReflection执行IndexDao的query实现方法:

  其中getIntroductionDelegateFor方法中的delegate通过反射对默认实现类型进行构造方法实例化后调用实例化的方法,由此可以看出上面的第二次打印结果没有打印前置通知的内容,因为此时IndexoDao的对象是原对象,不是代理对象:

  总结:Introductions(引用)通过 @DeclareParents 注解实现,可以给一个空白类进行方法复制,它通过解析@DeclareParents 注解信息,代理时将定义的静态接口变量作为它的父类,并实现它的方法,方法执行时调用的是defaultImpl 指定的类模板的实现方法;

  参考:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-introductions

Spring(11) - Introductions进行类扩展方法相关推荐

  1. java params 参数_将params作为参数传递给类扩展方法的函数

    我正在尝试将函数作为参数传递给类扩展方法 . 做的时候 fun Router.handleJsonGet(path: String, method: () -> Any) { this.get( ...

  2. 线性判别函数(Python实现批感知器算法、Ho Kashyap算法和MSE多类扩展方法)——模式识别编程作业

    文章目录 写在前面 批感知器算法 Ho Kashyap算法 MSE多类扩展方法 Ref. 写在前面 本博客为模式识别作业的记录,实现批感知器算法.Ho Kashyap算法和MSE多类扩展方法,可参考教 ...

  3. 系统类扩展方法,实现对所有类或某种类扩展自定义方法

    扩展方法的格式: 1.必须把扩展方法写在静态类中 2.扩展方法的第一个参数必须加 "this" 修饰 例如,对所有object对象的扩展方法IsEmptyOrNull,判断对象是否 ...

  4. c# 通用类扩展方法 备注

    using System; using System.Collections.Generic; using System.Linq; using System.Text;namespace Commo ...

  5. 基本语法及基本概念概述(标识符、访问修饰符、变量、数组、枚举、注释、空行、继承、接口、(对象、类、方法、实例变量)、关键字表)

    文章目录 1.标识符 2.标识符命名规范 3.访问修饰符 4.变量 5.数组 6. 枚举 7.注释 8.空行 9.继承 10.接口 11.对象.类.方法.实例 12.关键字表 13.保留字(reser ...

  6. 如何使用 C# 扩展方法

    译文链接:https://www.infoworld.com/article/3130492/how-to-work-with-extension-methods-in-c.html C# 在 3.0 ...

  7. 在C#中,当您在null对象上调用扩展方法时会发生什么?

    本文翻译自:In C#, what happens when you call an extension method on a null object? Does the method get ca ...

  8. iOS中分类(category)和类扩展(Extension)的区别

    iOS中分类(category)和类扩展(Extension)的区别 一.分类的定义: 分类是OC中的特有语法,它是表示一个指向分类结构体的指针,它是为了扩展系统类的方法而产生的一种方式. 二.分类的 ...

  9. C#扩展方法和静态类详解

    1.静态方法属于类,而普通方法则属于对象,因此静态方法可以用类名.静态方法 来调用,而普通方法则必须用new来实例化后调用 2.静态类中只能有 静态的方法,属性和变量 3.普通类中能有普通方法,也能有 ...

  10. ASP.Net string 类的扩展方法 [转]

    string 类的扩展方法列表(基本相同于 IEnumerable<T> 接口的成员列表): Aggregate<> //累加 All<> //是否都满足条件 An ...

最新文章

  1. 用Ajax请求服务器的图片,并显示在浏览器中(转)
  2. Prometheus + Granafa 构建高大上的MySQL监控平台
  3. Java从入门到精通08-二进制、位运算、移位运算
  4. SpringBoot 后台管理系统
  5. 周思进:自知“能力不足“让我专注十几年音视频
  6. android wear 处理器,联发科推Android Wear平台可穿戴处理器
  7. 使用JdbcTemplate报 Incorrect column count: expected 1, actual 5错误解决
  8. [独库骑行之奇山异石]丹霞地貌和雅丹地貌
  9. leetcode—11.队列题型python解答
  10. AD9361官方例程发送端数据流向
  11. 《摄影测量学》空间后方交会详细解读
  12. 2011年分形艺术国际大赛比赛规则
  13. android ding铃声,Ring a Ding Dong
  14. ireport oracle,用ireport调用oracle存储过程
  15. bugku ctf 备份是个好习惯 (听说备份是个好习惯)
  16. 计算机二级考试主要学什么,计算机二级考试需要学习什么内容
  17. Android:辅助功能(模拟点击,模拟手势)入门基本学习
  18. T-BOX 车载网联终端设计
  19. 2020好用的C++编译器有哪些?这几款值得下载
  20. java抛硬币_Java程序抛硬币

热门文章

  1. win FlashFxp与ubuntu vsftpd共享文件
  2. 7个实用有效的shopify运营策略,跨境电商卖家必知
  3. 北航计算机考博经验,北京航空航天大学考博经历
  4. CADD课程学习(13)-- 研究蛋白小分子动态相互作用-II(水中的溶菌酶 GROMACS)
  5. 《走出幻觉,走向成熟》--读书笔记1
  6. Jenkins项目配置-maven项目-全面
  7. 2021年网络安全省赛--web隐藏信息探索解析(中职组)
  8. 三国时代微博(佩服博主琢磨先生太有才了!)
  9. VMWare虚拟机启动img文件
  10. Portable Batch System