AOP
AOP(Aspect Oriented Programming),面向切面编程。
原本的面向对象编程(OOP)是将一类实体的共有行为抽象成一个公共的类,共有行为既包含核心功能,又包含一些公共行为(比如,日志、权限、缓存、同步、事务等)。这些公共行为重复出现在每个类中,造成了大量的冗余,也不利用各个模块的重用。
面向切面编程(AOP)将这些公共行为抽取出来,每一种公共行为(横切关注点)可以配置成一个“通知(advice)”,利用动态代理,可以让“通知”在需要的地方执行,需要执行的地方我们称为“切入点(Pointcut)”,通知和切入点构成一个“切面(Aspect)”。这种将纵向封装的对象“横向切开”,然后“织入(weave)” 通知,实现功能增强的思想就是面向切面编程。
AOP依赖的jar包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>使用AOP的三种方式
- 测试程序
- 被代理的接口
public interface UserService { void add(); void delete(); void update(); void select(); } - 真实对象:接口的一个实现类
public class UserServiceImpl implements UserService { public void add() { System.out.println("增加"); } public void delete() { System.out.println("删除"); } public void update() { System.out.println("修改"); } public void select() { System.out.println("查询"); } }
- 被代理的接口
1. 方式1
- 使用Spring提供的API接口定义能够确定织入位置的“通知”,在配置文件中实现“织入”。
- Spring API定义“通知”
/** * aop使用方式一: * 1. 通过Spring提供的API接口实现【通知】 * 2. 目标类和通知类都配置成bean * 3. 【目标对象】配置成【切入点】 * 4. 通知类配置成【通知】 * 5. Spring通过动态代理生成【代理对象】 * 6. 根据配置文件实现功能增强 * */ public class Log implements MethodBeforeAdvice { /** * 通过Spring提供的接口实现前置增强(前置的通知),在method执行之前自动调用 * @param method 目标对象的方法(被增强的方法,切入点?) * @param args 方法参数 * @param target 目标对象,代理的真实对象 * @throws Throwable */ public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了"); } }public class afterLog implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName() + "的" + method.getName() + "方法执行完毕,并返回了结果:" + returnValue); } } - 配置文件:导入aop约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.jing.service.UserServiceImpl"/> <bean id="log" class="com.jing.log.Log"/> <bean id="afterLog" class="com.jing.log.afterLog"/> <aop:config> <!--切入点:被增强的方法, 切入点公式:execution(修饰符 返回值 类名 方法名 方法参数)--> <aop:pointcut id="pointcut" expression="execution(* com.jing.service.UserService.*(..))"/> <!--通知:增强的功能--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans> - 测试类
public class MyTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConfiguration.xml"); // 代理的是接口,所以是UserService.class UserService userService = applicationContext.getBean("userService", UserService.class); userService.add(); } } /** * 执行结果: * com.jing.service.UserServiceImpl的add方法被执行了 * 增加 * com.jing.service.UserServiceImpl的add方法执行了,并返回了结果:null */
- Spring API定义“通知”
2. 方式2
- 将扩展功能定义在一个类中,其他通过配置文件配置
- 自定义扩展功能类
/** * aop使用方式二: * 1. 将扩展功能定义在一个类当中。 * 2. 目标类和扩展功能类配置成bean * 3. 扩展功能类配置成【切面】 * 2. 在切面中,将扩展方法配置成【通知】,并且指明切入的位置 * 3. 配置【切入点】:某个方法、某个类的全部方法、某个包中的全部方法 */ // 将扩展功能定义在一个类中,然后通过配置文件确定功能执行的位置。 public class DiyPointcut { public void before(){ System.out.println("前置增强"); } public void after(){ System.out.println("后置增强"); } } - 配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.jing.service.UserServiceImpl"/> <bean id="log" class="com.jing.log.Log"/> <bean id="afterLog" class="com.jing.log.afterLog"/> <bean id="diyPointcut" class="com.jing.diy.DiyPointcut"/> <aop:config> <!--切面--> <aop:aspect ref="diyPointcut"> <!--切入点--> <aop:pointcut id="pointcut" expression="execution(* com.jing.service.UserService.*(..))"/> <!--通知:规定增强位置--> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans> - 测试类
public class MyTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConfiguration.xml"); // 代理的是接口,所以是UserService.class UserService userService = applicationContext.getBean("userService", UserService.class); userService.add(); } } /** 输出结果: 前置增强 增加 后置增强 */
- 自定义扩展功能类
3. 方式3
- 通过注解的方式使用AOP
- 自定义功能增强类+注解
@Aspect public class AnnotationPointcut { @Before("execution(* com.jing.service.UserServiceImpl.*(..))") public void before(){ System.out.println("前置增强"); } @After("execution(* com.jing.service.UserServiceImpl.*(..))") public void after(){ System.out.println("后置增强"); } @Around("execution(* com.jing.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); jp.proceed(); System.out.println("环绕后"); } } - 配置文件:开启注解支持
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.jing.service.UserServiceImpl"/> <bean id="log" class="com.jing.log.Log"/> <bean id="afterLog" class="com.jing.log.afterLog"/> <bean id="annocationPointcut" class="com.jing.diy.AnnotationPointcut"/> <!--支持开启注解支持:proxy-target-class默认是false,即基于JDK实现的动态代理(只能代理接口);反之是基于cglib--> <aop:aspectj-autoproxy proxy-target-class="false"/> </beans> - 测试类
public class MyTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConfiguration.xml"); // 代理的是接口,所以是UserService.class UserService userService = applicationContext.getBean("userService", UserService.class); userService.add(); } } /** 环绕前 前置增强 增加 后置增强 环绕后 */
- 自定义功能增强类+注解
AOP应用场景
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
版权声明:本文为weixin_44250483原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。