什么是AOP
AOP的全称是Aspect Orient Programming,即面向切面编程。是对OOP(Object Orient Programming)的一种补充,战门用于处理一些具有横切性质的服务。常常用于日志输出、安全控制等。
优点:
1、降低模块之间的耦合度
2、使系统容易扩展
3、更好的代码复用。
AOP使用场景:
AOP用来封装横切关注点,具体可以在下面的场景中使用:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
AOP相关概念:
切面(Aspect) :官方的抽象定义为“一个关注点的模块化,这个关注点可能会横切多个对象”。
连接点(Joinpoint) :程序执行过程中的某一行为。
通知(Advice) :“切面”对于某个“连接点”所产生的动作。
切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。
目标对象(Target Object) :被一个或者多个切面所通知的对象。
AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。
spring aop通知(advice)分成五类:
前置通知[Before advice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。
正常返回通知[After returning advice]:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。
异常返回通知[After throwing advice]:在连接点抛出异常后执行。
返回通知[After (finally) advice]:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。
环绕通知[Around advice]:环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。
怎么在原来类的实现的基础上添加逻辑代码(在不修改源代码的情况下,可以实现功能的增强)。
刚开始说到是对OOP的一种补充,具体补充的是什么呢?考虑一种情况,如果我们需要在所有方法里打印一句日志。
按照OOP的处理思想,1>直接在源代码方法中加日志
2>在不修改源代码的情况下重写一个类,再编写一个日志打印
3>用继承,重写。在不修改源代码的情况下重新创建一个类,再编写一个日志打印,并调用源代码中的方法。这就是面向对象编程思想。
但是如果要求我们在业务方法开始或结束时再打印一些日志呢?看起来一个比一个简单,其实还是很繁琐,这样始终不是办法,而且我们总是在改业务方法,在业务方法里面掺杂了太多的其他操作,侵入性太高。
所以,我们可以用AOP
下面,简单写一个小例子
1>导包(在原有spring项目上,添加aspectj-1.8.9.jar和aspectjweaver-1.8.1.jar)
2>新建通知类MyAdvice.java
package cn.xxs.advice;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
/**
* 前置通知
* @param joinpoint
*/
public void before() {
System.out.println("before");
}
/**
* 后置通知
*/
public void after() {
System.out.println("after");
}
/**
* 引入通知
*/
public void afterReturning() {
System.out.println("afterReturning");
}
/**
* 环绕通知
*/
public void around(ProceedingJoinPoint joinpoint) {
System.out.println("around开始");
try {
joinpoint.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("around结束");
}
/**
* 异常通知
*/
public void afterThrowing() {
System.out.println("afterThrowing");
}
}
3>创建接口UserService.java
package cn.xxs.service;
public interface UserService {
public void print();
}
4>创建接口的实现类UserServiceImpl.java
package cn.xxs.service.impl;
import cn.xxs.service.UserService;
import cn.xxs.util.BeanUtil;
public class UserServiceImpl implements UserService{
@Override
public void print() {
System.out.println("打印");
}
}
5>配置bean.xml配置文件
<?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"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/context/spring-tx.xsd
">
<!-- 把UserServiceImpl交给spring管理 -->
<bean id="userService" class="cn.xxs.service.impl.UserServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean id="myAdvice" class="cn.xxs.advice.MyAdvice"></bean>
<!-- 配置aop -->
<aop:config>
<!-- 配置切面,用于各种通知 -->
<aop:aspect ref="myAdvice">
<!-- 配置aop -->
<!-- expression :配置加入的具体位置 -->
<aop:pointcut expression="execution(public * *(..))" id="myPointcut"/>
<!-- 配置通知类型 -->
<aop:before pointcut-ref="myPointcut" method="before"/>
<aop:after pointcut-ref="myPointcut" method="after"/>
<aop:after-returning pointcut-ref="myPointcut" method="afterReturning"/>
<aop:around pointcut-ref="myPointcut" method="around"/>
<aop:after-throwing pointcut-ref="myPointcut" method="afterThrowing"/>
</aop:aspect>
</aop:config>
</beans>
6>创建测试代码UserAction.java
package cn.xxs.action;
import org.junit.Test;
import cn.xxs.service.UserService;
import cn.xxs.util.BeanUtil;
public class UserAction {
private UserService userService;
@Test
public void test() {
userService = (UserService) BeanUtil.getBean("userService");
userService.print();
}
}
7>创建工具类BeanUtil.java
package cn.xxs.util;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanUtil {
public static Object getBean(String beanName) {
return new ClassPathXmlApplicationContext("bean.xml").getBean(beanName);
}
}
测试结果: