Aspect Oriented Programming ,即面向切面编程。java
下面是AOP的一个示意图
spring
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.11.RELEASE</version> </dependency>
动态代理的类的方法应当都由接口来实现,这样才方便使用动态代理对象执行方法
编程
高耦合的写法,每次打印日志都要手动完成:
框架
上方代码中,日志信息和业务逻辑的耦合性很高,不利于代码的维护。使用AOP能够进行优化,咱们可使用动态代理实现AOP:
给业务代码找一个代理,打印日志信息的工做交给代理来作。这样的话业务代码就只须要关注自身业务便可。
(1)去掉手动输出的日志信息
(2).代理辅助类的编写和使用(动态代理的核心)模块化
咱们建立的并非所谓的代理类,而是一个能够帮助咱们返回代理对象的辅助类,这个辅助类有两个功能测试
动态代理实现AOP比较复杂,不易理解。Spring框架对AOP进行了封装,使用Spring框架能够用面向对象的思想实现AOP。Spring框架中不须要建立辅助类,只须要建立一个切面对象,将全部的非业务代码在切面对象中完成便可(但实际上Spring框架底层依然会根据切面类和代理类来生成代理对象。)优化
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.11.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.11.RELEASE</version> </dependency>
当使用Spring实现时,这一步非必须!直接在实体类里面定义方法也可
3d
注意须要加上Component注解把他交给IoC
代理
类定义处的两个注解日志
@Aspect
表示该类是一个切面类@Component
将该类的对象注入到IoC容器(切面类和实体类都须要加上这个注解)方法处的注解
@Before
表示方法执行的具体位置和时机是方法开始时
@After
相似Before,不过位置是方法的最后
@AfterReturning
在下文有做解释
@AfterThrowing
在下文有做解释
context:component-scan
指扫描com.pedro包中的全部类,若是该类同时添加了component注解,则将该类扫描IoC容器中。即IoC管理它的对象aop:aspectj-autoproxy
让Spring容器结合切面类和目标类自动生成代理对象
用代理对象调用方法就会自动执行它自己的方法和切面类中的非业务代码
为何类名首字母要小写?
当使用注解配置bean时,默认id(别名)就是首字母改成小写的类名。若想修改,就在实体类的注解处加上自定义的名字便可。如@Component("test")
,这样的话在getBean的时候就可使用自定义的别名了,即xx.getBean("test")
(1)AfterReturning
用于在获取返回值后执行一段非业务代码
注:由于有两个参数,这里的value标签名被标出,而上面的before、after等注解只有一个参数,因此省略了value
结合上面的其余注解,会输出:
div方法的参数是[6,2] div方法执行完毕 div方法的结果是3
(2)AfterThrowing
切面类的AfterThrowing注解,用于在抛出异常后执行一段非业务代码
结合上面的其余注解,会输出:
div方法的参数是[6,0] div方法执行完毕 div方法抛出的异常:java.lang.ArithmeticException: / by zero
2021.4.3