前言

最近想起来在博客【详解什么是Spring AOP】 里面挖了一个坑没有填。那就是Introduction部分的内容,当时说要写一个小例子讲一下,这个东西是怎么用的。直接就给忘了,这次就是把这个坑填上的。更多Spring内容进入【Spring解读系列目录】。

Introductions 初识

首先我们还是看官网怎么说的【Introductions】,以下英文部分来自官方文档:

Introductions (known as inter-type declarations in AspectJ) enable an aspect to declare that advised objects implement a given interface, and to provide an implementation of that interface on behalf of those objects.
You can make an introduction by using the @DeclareParents annotation. This annotation is used to declare that matching types have a new parent (hence the name). For example, given an interface named UsageTracked and an implementation of that interface named DefaultUsageTracked, the following aspect declares that all implementors of service interfaces also implement the UsageTracked interface (to expose statistics via JMX for example):

前一段是概念,Introductions能够是一个切面去声明一个已经通知过的对象去实现给定的接口,并且提代表这些对象供一个接口的实现。后面一段主要是说怎么用的,主要就是用@DeclareParents 这个注解。概念说的很绕,其实就是在使用中就是给某一个类A指定一个父类B。而且类A本来没有继承B,经过这个概念以后,就完成了继承。@DeclareParents看这个注解的名字也是非常的耿直,声明父类。

参考下官方文档的例子。就是在切面类中给一个接口加上@DeclareParents注解,然后指定接口的路径,再给一个默认的实现类,下面代码来自官网。

@Aspect
public class UsageTracking {//给com.xzy.myapp.service包下的所有接口指定一个默认的实现类@DeclareParents(value="com.xzy.myapp.service.*+", defaultImpl=DefaultUsageTracked.class) public static UsageTracked mixin;@Before("com.xyz.myapp.SystemArchitecture.businessService() && this(usageTracked)")public void recordUsage(UsageTracked usageTracked) {usageTracked.incrementUseCount();}
}

怎么访问这个bean呢?官网也说了,和一般的bean没有区别,直接用就好了。那么随后我们就自己写一个小例子来验证官网这个说法。

The interface to be implemented is determined by the type of the annotated field. The value attribute of the @DeclareParents annotation is an AspectJ type pattern. Any bean of a matching type implements the UsageTracked interface. Note that, in the before advice of the preceding example, service beans can be directly used as implementations of the UsageTracked interface. If accessing a bean programmatically, you would write the following:
UsageTracked usageTracked = (UsageTracked) context.getBean(“myService”);

Introductions Sample

既然要用例子讲,那就还是得写几个例子。假设我们有一个接口TargetDao,一个实现类DemoDao,一个切面类DemoAspect,还有一个毫不相关的类IntroduDemoDao,以及一个测试类DemoTest。这个类将会给我们展示什么是Introductions。

public interface TargetDao {public void print();public void print(String a);public void print(Integer a);
}
@Repository("demodao")
public class DemoDao implements TargetDao{public void print(){System.out.println("print empty");  //打印测试}
}
@Component
@Aspect
public class DemoAspect {@DeclareParents(value = "com.demo.dao.*", defaultImpl = DemoDao.class)public static TargetDao targetDao;
}
@Repository("introDao")
public class IntroduDemoDao { //这个类是空的
}
public class DemoTest {public static void main(String[] args) {AnnotationConfigApplicationContext anno=new AnnotationConfigApplicationContext(Appconfig.class);TargetDao targetDao= (TargetDao) anno.getBean("introDao");targetDao.print();}
}

写完了,直接运行。如果按照常理,一定会报错的。因为我们要拿出来的IntroduDemoDao根本就没有任何的实现(其实连内容都没有),也没有对任何的对象进行初始化,不报错不可能的。但是这里运行以后却把print empty这行打印出来了,是不是见鬼了。我们现在这个例子,就是把introDao拿出来,但是introDao这里没有任何方法,没有实现任何接口,但是却能调用方法打印东西, 而且是最终执行的是DemoDao.print()方法。这是为什么呢?

先不解释这个问题,如果我们把切面类里的下面这两句删掉,一定会报错。

@DeclareParents(value = "com.demo.dao.*", defaultImpl = DemoDao.class)
public static TargetDao targetDao;删掉上面两行,运行结果:报错------------------------------
Exception in thread "main" java.lang.ClassCastException: com.demo.dao.IntroduDemoDao cannot be cast to com.demo.dao.TargetDaoat com.demo.main.DemoTest.main(DemoTest.java:13)

Introductions解析

要解释这个原因,首先得分析报错。我们看这里报的是强转错误,因为IntroduDemoDaoTargetDao完全是两个东西,不可能强转成功,更不可能去调用方法。但是(注意这个但是)加上就没有问题了,所以回到@DeclareParents这个注解,直接翻译就是声明父类。解释到这里有没有小伙伴恍然大悟呢?

按照Spring官网他叫Introduction,但是实际表现可以认为是指定父类。那么这个怎么理解呢,就是首先找到com.demo.dao下的所有类,然后让他去引入TargetDao接口的DemoDao实现。就是说我现在com.demo.dao.*这个写法,就是让dao包下所有的类都去实现TargetDao。既然是要实现TargetDao就得把这里面的方法实现了对不对。这个实现肯定不是Spring做的,Spring在这里做的就是去找TargetDao的实现类,于是就找到了DemoDao。然后就把DemoDao里面实现的方法给贴过来作为IntroduDemoDao的实现方法,所以当我们调用print()的时候,执行的是DemoDao.print()

如果我们把IntroduDemoDao里面也实现了TargetDao,那么执行的就是IntroduDemoDao里面的方法了。因为我们这里只是给没有实现的那些类指定一个默认的实现类,如果有真正的实现还是会用真正的实现类去做的,比如我们给IntroduDemoDao实现TargetDao接口,再运行看看结果:

@Repository("introDao")
public class IntroduDemoDao implements TargetDao{ //实现TargetDaopublic void print() {System.out.println("IntroduDemoDao empty");  //测试打印}
}运行结果:
IntroduDemoDao empty  ------> 这次打印就是IntroduDemoDao里面的内容了。

总结

所以Introduction做了什么事情呢?就是给我们要实现的类指定一个父类,并且指定一个默认实现的类。

Spring AOP Introductions相关推荐

  1. Spring Aop 组件概述

    Spring Aop 概述 AOP(Aspect-Oriented Programming) 面向切面编程, 这种编程模型是在 OOP(Object-Oriented Programming) 的基础 ...

  2. Spring AOP源码解析(二)—— AOP引入

    目录 配置类 AopAutoConfiguration AspectJAutoProxyingConfiguration ClassProxyingConfiguration @EnableAspec ...

  3. 一步一步手绘Spring AOP运行时序图(Spring AOP 源码分析)

    相关内容: 架构师系列内容:架构师学习笔记(持续更新) 一步一步手绘Spring IOC运行时序图一(Spring 核心容器 IOC初始化过程) 一步一步手绘Spring IOC运行时序图二(基于XM ...

  4. 【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory...】

    每篇一句 基础技术总是枯燥但有价值的.数学.算法.网络.存储等基础技术吃得越透,越容易服务上层的各种衍生技术或产品 相关阅读 [小家Spring]Spring AOP原理使用的基础类打点(AopInf ...

  5. Spring AOP官网学习

    Spring AOP官网学习 5.1 AOP概念 让我们从定义一些核心的AOP概念和术语开始.这些术语并不是spring特有的.不幸的是,AOP术语不是特别直观. 1.Aspect(方面):跨多个类的 ...

  6. Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象【两万字】

      基于最新Spring 5.x,介绍了Spring AOP中的AspectJAwareAdvisorAutoProxyCreator自动代理创建者的工作流程,对于创建代理对象的源码进行了深度分析! ...

  7. Spring AOP + Redis解决重复提交的问题

    Spring AOP + Redis解决重复提交的问题 用户在点击操作的时候,可能会连续点击多次,虽然前端可以通过设置按钮的disable的属性来控制按钮不可连续点击,但是如果别人拿到请求进行模拟,依 ...

  8. 利用Spring AOP与JAVA注解为系统增加日志功能

    Spring AOP一直是Spring的一个比较有特色的功能,利用它可以在现有的代码的任何地方,嵌入我们所想的逻辑功能,并且不需要改变我们现有的代码结构. 鉴于此,现在的系统已经完成了所有的功能的开发 ...

  9. Spring AOP的一些概念

            切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子. 在Spring AOP中,切面可以使用通用类(基于模 ...

  10. Spring AOP与IOC

    Spring AOP实现日志服务 pom.xml需要的jar <dependency><groupId>org.apache.commons</groupId>&l ...

最新文章

  1. JS:1.2,控制语句(if,if else,for,switch,while,do while)
  2. golang if 条件判断语句 简介
  3. 关闭笔记本显示器指定组合键才能打开_笔记本外接显示器怎么设置 笔记本外接显示器设置方法【详解】...
  4. OCA读书笔记(1) - 浏览Oracle数据库架构
  5. 现代制造工程02:第一部分——刀具(含2个易考点)
  6. Servlet 3的异步Servlet功能
  7. java+connect+time+out_聊聊jdk httpclient的connect timeout异常
  8. SCCM2012系列之十二,SCCM2012部署操作系统
  9. java面试资料整理(高级必备)
  10. Mac下Android 反编译
  11. C语言也能干大事第十四节(如鹏基础)
  12. 邮政出面打假?中国邮政是否考虑搭建其品牌官网?
  13. 计算机管理的显卡驱动,显卡驱动,教您显卡驱动怎么安装
  14. 使用node加密excel文件
  15. 《NVMe-over-Fabrics-1_0a-2018.07.23-Ratified》阅读笔记(1)
  16. Echarts实现省级地图的两种方法(以浙江省为例)
  17. 前任写的代码,真是辣鸡…
  18. kalibr编译 error: ‘Eigen::MatrixBase<Derived>::~Matrix
  19. 构造方中的this关键字
  20. 网易云音乐怎么设置黑胶唱片_黑胶唱片是否是开放音乐格式?

热门文章

  1. 百年铁树要开花,贾跃亭要还钱了?
  2. XMU 1613 刘备闯三国之三顾茅庐(一) 【并查集】
  3. 自我监督学习:提高深度学习数据效率的计划
  4. Server 2008系统安装驱动提示“无法验驱动程序数字签名”怎么办?
  5. 北京航空航天大学计算机学院 赵,北京航空航天大学计算机学院计算机应用技术导师介绍:夏春和...
  6. easyui动态修改required
  7. PyQt5简易入门指南02,简单图片显示程序
  8. DH-SQL(学生信息表-课程表-选课表)
  9. 一网打尽“小黄图”!手把手教你造一只AI鉴黄神器(内附代码及数据集)
  10. 北京地铁,把什么丢了?