一、Spring的AOP
AOP的思想:是Aspect oritention programming面想切面编程的简写。把一个个横切关注点(零散存在于业务方法中的功能代码)放进某一个模块中去,我们称这个模块为一个切面。每一个切面都能影响业务的某一个功能,切面的目的就是为了增强。
AOP的目的:AOP能将与业务无关、但是又为业务模块所共同调用的逻辑或其他内容进行封装;减少代码重复率,降低模块之间的耦合度,提高后期的可维护性。
AOP的优势:降低模块的耦合度、让系统更容易扩展、提高后期可维护度。换句话说就是,把多个方法前后相同的代码抽取出来,使用动态代理的方式来控制。运行的时候,先执行抽取出来的方法,再执行真实的方法。
AOP中的一些概念:
Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。
Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强
Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。
使用AOP之前,下面三中方法中(权限控制、日志控制、事务控制),存在大量的代码冗余,不利于后期维护。
使用AOP之后,抽取共同的代码部分(权限控制、日志控制、事务控制),需要使用的时候再插入,可大大降低重复代码量,提高后期的可维护性。
二、PointCut语法
PointCut语法的作用,就是为了表达在哪些方法上,使用哪些方法对它进行增强。
AspectJ切入点语法如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
翻译成中文:
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
?:表示可以出现一次,或者不出现.没有问号,表示必须出现一次.
通配符:
*:匹配任何部分,只能表示一个单词
…: 可用于全限定名中和方法参数中,分别表示子包和0到N个参数
举例:
1、表示所有的public方法
execution(public * *(..))
2、表示所有以set开头方法
execution(* set*(..))
3、表示所有由method接口定义的任何方法
execution(* com.xyz.service.method*(..))
4、表示所有在service包下的方法
execution(* com.xyz.service.*.*(..))
5、表示所有在service包下,包括其子包中的方法
execution(* com.xyz.service..*.*(..))
三、使用xml方式实现AOP
1、导入依赖包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
2、创建包、类,目录结构如下:
3、各个类中方法的撰写
Transaction类(需要被增强的类),里面包含两个方法,一个能正常执行的insert()方法,一个主动抛出异常的delete()方法。
public class Transaction {
public void insert(){
System.out.println("插入数据!!!");
}
public void delete(){
System.out.println("删除数据!!!");
System.out.println(1/0);
}
}
TransactionManager类(使用里面的方法,去增强其他的类),里面包含四个方法,在不同时期对需要被增强的方法进行增强。
public class TransactionManager {
public void before(){
System.out.println("before前置增强!");
}
public void afterReturning(){
System.out.println("afterReturning后置增强!");
}
public void throwing(){
System.out.println("throwing异常增强!");
}
public void after(){
System.out.println("after最终增强!");
}
}
applicationContext.xml文件
<!--把这两个类交给spring管理 -->
<bean id="transaction" class="com.springaop.service.Transaction"></bean>
<bean id="transactionManager" class="com.springaop.tx.TransactionManager"></bean>
<!--AOP配置 -->
<aop:config>
<!--表示哪里的方法需要进行增强-->
<aop:pointcut id="txPointCut" expression="execution(* com.springaop.service.*.*(..))"/>
<!--增强的方法从哪个类中获取-->
<aop:aspect ref="transactionManager">
<!--四种增强方法-->
<aop:before method="before" pointcut-ref="txPointCut"/>
<aop:after-returning method="afterReturning" pointcut-ref="txPointCut"/>
<aop:after-throwing method="throwing" pointcut-ref="txPointCut"/>
<aop:after method="after" pointcut-ref="txPointCut"/>
</aop:aspect>
</aop:config>
TransactionTest测试类
//使用spring的测试方式
@RunWith(SpringJUnit4ClassRunner.class)
//导入spring配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class TransactionTest {
@Autowired
private ApplicationContext context;
@Test
public void test1(){
Transaction transaction = context.getBean(Transaction.class);
transaction.insert();
}
@Test
public void test2(){
Transaction transaction = context.getBean(Transaction.class);
transaction.delete();
}
}
运行结果:
1、test1()方法的执行结果如下,可以看到该方法正常执行,增强方法也执行了。
2.test2()方法的执行结果如下,可以看到,我们主动编写的除零异常产生了,于是执行了异常增强方法。
四、使用注解方式实现AOP
1、导入依赖包
同上
2、创建类和包
同上
3、各个类中方法的撰写
Transaction类:同上
TransactionManager类(类上贴上Aspect注解,每个方法都贴上对应增强时期的注解)
@Aspect
public class TransactionManager {
@Before("execution(* com.springaop.service.Transaction.*(..))")
public void before(){
System.out.println("before前置增强!");
}
@AfterReturning("execution(* com.springaop.service.Transaction.*(..))")
public void afterReturning(){
System.out.println("afterReturning后置增强!");
}
@AfterThrowing("execution(* com.springaop.service.Transaction.*(..))")
public void throwing(){
System.out.println("throwing异常增强!");
}
@After("execution(* com.springaop.service.Transaction.*(..))")
public void after(){
System.out.println("after最终增强!");
}
}
applicationContext.xml文件,开启AOP注解扫描即可
<!--把这两个类交给spring管理 -->
<bean id="transaction" class="com.springaop.service.Transaction"></bean>
<bean id="transactionManager" class="com.springaop.tx.TransactionManager"></bean>
<!--AOP注解扫描 -->
<aop:aspectj-autoproxy/>
TransactionTest测试类,同上
运行结果:
1、test1()方法的执行结果如下,正常执行。
2.test2()方法的执行结果如下,达到预期效果。