1.AOP面向切面编程
1.1. AOP介绍
OOP(Object Oriented Programming ) 面向对象编程,万物皆对象!
AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。
OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,即切面。"切面"简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。
1.2. AOP图解
Spring框架底层使用的代理设计模式来完成AOP!
通过动态代理,可以在指定位置执行对应流程。这样就可以将一些横向的功能抽离出来形成一个独立的模块,然后在指定位置插入这些功能。这样的思想,被称为面向切面编程,亦即AOP。
2.AOP术语
1.target目标类:需要被代理的类。例如:UserServiceImpl
2.Joinpoint(连接点):就是AOP创建了代理对象之后,这个代理对象对应的真实对象中
可能会增强的点称为连接点
3.PointCut (切入点):一定会被增强的连接点称为切入点,一个切入点一定是连接点,一个连接点不一定是切入点
4.advice (通知/增强):通知的前提是需要有一个通知类,通知其实就是切入点增强过程中做的事情
普通通知:
前置通知 切入点执行之前
后置通知 切入点执行之后
异常通知 切入点执行过程中发生异常
最终通知 切入点在执行过程中无论是后置通知还是执行异常通知都会执行最终通知高级通知:
环绕通知 一个顶四
5.Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程。理论 主要作用是用于说明切入点与通知的关系
6.proxy (代理类):通知+切入点(由动态代理自动生成的类)
7.Aspect(切面):是切入点pointcut和通知advice的结合
8.引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
3.Spring的AOP
3.1 Spring AOP基于xml
准备操作对象
public class CarServiceImpl implements CarService {
public Integer add(Car c) {
System.out.println("新增Car到数据库:"+c);
return 1;
}
public Integer update(Car c) {
System.out.println("更新Car到数据库:"+c);
return 1;
}
}
在想要的server前面添加增强类
public class TransactionTx {
/**
* 前置增强(通知)
*/
public void openTx(JoinPoint joinPoint){
Object target = joinPoint.getTarget(); //目标类对象
Object proxyObject = joinPoint.getThis(); //代理类对象
Signature signature = joinPoint.getSignature(); //目标方法
String name = signature.getName();//目标方法名字
int modifiers = signature.getModifiers();//目标方法修饰符
Object[] args = joinPoint.getArgs(); // 方法的参数
System.out.println("-前置增强(通知)---开启事务---,目标方法的方法名:"+name+",方法参数:"+ Arrays.toString(args));
}
/**
* 返回增强(返回通知) 后置通知(目标方法如果执行有异常,那么异常通知执行,返回通知不执行!)
*/
public void commitTx(JoinPoint joinPoint,Object result){
System.out.println("--返回增强(返回通知)--提交事务---:返回值:"+result);
}
/**
* 异常增强(通知)
* 目标方法如果执行有异常,那么异常通知执行,返回通知不执行!
* 目标方法没有异常,那么正常执行,执行返回通知
*/
public void rollbackTx(JoinPoint joinPoint,Throwable e){
System.out.println("--异常增强(通知)--回滚事务--- 异常啦:"+e.getMessage());
}
/**
* 最终增强(通知):无论目标方法是否有异常,都会执行!
*/
public void finnalMethod(JoinPoint joinPoint){
System.out.println("--最终增强(通知)--释放系统资源--");
}
/**
* 环绕通知
* @param joinPoint
* @return
*/
public Object aroundMethod(ProceedingJoinPoint joinPoint) {
Object target = joinPoint.getTarget(); //目标类对象
Object proxyObject = joinPoint.getThis(); //代理类对象
Signature signature = joinPoint.getSignature(); //目标方法
String name = signature.getName();//目标方法名字
int modifiers = signature.getModifiers();//目标方法修饰符
Object[] args = joinPoint.getArgs(); // 方法的参数
Object result=null;
try {
System.out.println("---环绕(前)---开启事务---,目标方法的方法名:"+name+",方法参数:"+ Arrays.toString(args));
//调用目标类目标方法
result=joinPoint.proceed();
System.out.println("---环绕(返回)---提交事务---:返回值:"+result);
} catch (Throwable e) {
//e.printStackTrace();
System.out.println("--环绕(异常)--回滚事务--- 异常啦:"+e.getMessage());
} finally {
System.out.println("--环绕(最终)--释放系统资源--");
}
return result;
}
织入目标对象(xml)
<!--增强类对象-->
<bean id="tx" class="com.it.tx.TransactionTx"/>
<!--目标类对象-->
<bean id="carService" class="com.it.service.impl.CarServiceImpl"/>
<!--配置切面(告诉Spring框架,哪些类中的哪些方法需要被代理,如何代理)-->
<aop:config>
<!--pointcut:切入点表达式(哪个类中哪个方法需要被代理)-->
<aop:pointcut id="pc" expression="execution(* com.it.service.impl.*.*(..))"/>
<!--如何代理,目标方法之前还是之后?-->
<aop:aspect ref="tx">
<!--前置增强-->
<aop:before method="openTx" pointcut-ref="pc"/>
<!-- 返回增强(返回通知) 后置通知-->
<aop:after-returning method="commitTx" returning="result" pointcut-ref="pc"/>
<!--环绕通知-->
<aop:around method="aroundMethod" pointcut-ref="pc"/>
<!--异常通知-->
<aop:after-throwing method="rollbackTx" throwing="e" pointcut-ref="pc"/>
<!--最终通知-->
<aop:after method="finnalMethod" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
<!--默认值false 表示使用JDK动态代理
true 使用CGLIB动态代理,但是如果没有接口,不管ture false 都是CGLIB代理!
-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
切入点表达式(可以使用通配符)
测试
@Test
public void test1(){
ClassPathXmlApplicationContext factory = new ClassPathXmlApplicationContext("cars.xml");
CarService carService = factory.getBean(CarService.class);
ComputerService computerService = factory.getBean(ComputerService.class);
Integer count = carService.add(new Car(1, "BMW", "川A3244"));
System.out.println(count>0?"新增成功":"新增失败");
}
3.2Spring中AOP基于注解
添加配置类
@ComponentScan("com.it")
@EnableAspectJAutoProxy(proxyTargetClass = false) //默认使用JDK动态代理
public class SpringConfig {
}
添加操作对象
@Service
public class CarServiceImpl implements CarService {
public Integer add(Car c) {
System.out.println("新增Car到数据库:"+c);
return 1;
}
public Integer update(Car c) {
System.out.println("更新Car到数据库:"+c);
return 1;
}
}
添加增强类
@Aspect //增强类
@Component
@Order(1)
public class TransactionTx {
/**
* 前置增强(通知)
*/
@Before(value = "execution(* com.it.service.impl.*.*(..))")
public void openTxB(JoinPoint joinPoint){
Object target = joinPoint.getTarget(); //目标类对象
Object proxyObject = joinPoint.getThis(); //代理类对象
Signature signature = joinPoint.getSignature(); //目标方法
String name = signature.getName();//目标方法名字
int modifiers = signature.getModifiers();//目标方法修饰符
Object[] args = joinPoint.getArgs(); // 方法的参数
System.out.println("-TransactionTx--B--前置增强(通知)---开启事务---,目标方法的方法名:"+name+",方法参数:"+ Arrays.toString(args));
}
@Before(value = "execution(* com.it.service.impl.*.*(..))")
public void openTxA(JoinPoint joinPoint){
Object target = joinPoint.getTarget(); //目标类对象
Object proxyObject = joinPoint.getThis(); //代理类对象
Signature signature = joinPoint.getSignature(); //目标方法
String name = signature.getName();//目标方法名字
int modifiers = signature.getModifiers();//目标方法修饰符
Object[] args = joinPoint.getArgs(); // 方法的参数
System.out.println("-TransactionTx--A--前置增强(通知)---开启事务---,目标方法的方法名:"+name+",方法参数:"+ Arrays.toString(args));
}
/**
* 返回增强(返回通知) 后置通知(目标方法如果执行有异常,那么异常通知执行,返回通知不执行!)
*/
//@AfterReturning(value = "execution(* com.it.service.impl.*.*(..))",returning = "result")
public void commitTx(JoinPoint joinPoint,Object result){
System.out.println("--返回增强(返回通知)--提交事务---:返回值:"+result);
}
/**
* 异常增强(通知)
* 目标方法如果执行有异常,那么异常通知执行,返回通知不执行!
* 目标方法没有异常,那么正常执行,执行返回通知
*/
//@AfterThrowing(value = "execution(* com.it.service.impl.*.*(..))",throwing = "e")
public void rollbackTx(JoinPoint joinPoint,Throwable e){
System.out.println("--异常增强(通知)--回滚事务--- 异常啦:"+e.getMessage());
}
/**
* 环绕通知
* @param joinPoint
* @return
*/
//@Around(value = "execution(* com.it.service.impl.*.*(..))")
public Object aroundMethod(ProceedingJoinPoint joinPoint) {
Object target = joinPoint.getTarget(); //目标类对象
Object proxyObject = joinPoint.getThis(); //代理类对象
Signature signature = joinPoint.getSignature(); //目标方法
String name = signature.getName();//目标方法名字
int modifiers = signature.getModifiers();//目标方法修饰符
Object[] args = joinPoint.getArgs(); // 方法的参数
Object result=null;
try {
System.out.println("---环绕---开启事务---,目标方法的方法名:"+name+",方法参数:"+ Arrays.toString(args));
//调用目标类目标方法
result=joinPoint.proceed();
System.out.println("---环绕---提交事务---:返回值:"+result);
} catch (Throwable e) {
//e.printStackTrace();
System.out.println("--环绕--回滚事务--- 异常啦:"+e.getMessage());
} finally {
System.out.println("--环绕--释放系统资源--");
}
return result;
}
/**
* 最终增强(通知):无论目标方法是否有异常,都会执行!
*/
//@After(value = "execution(* com.it.service.impl.*.*(..))")
public void finnalMethod(JoinPoint joinPoint){
System.out.println("--最终增强(通知)--释放系统资源--");
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class TestSpringAop {
@Autowired
CarService carService;
@Test
public void test1(){
Integer count = carService.add(new Car(1, "BMW", "川A3244"));
System.out.println(count>0?"新增成功":"新增失败");
}
}