1、AOP思想
1.1 什么是AOP
Aspect oritention programming(面向切面编程),把一个个的横切关注点(这些零散存在于业务方法中的功能代码,我们称之为横切面关注点)放到某个模块中去,称之为切面。那么每一个的切面都能影响业务的某一种功能,切面的目的就是功能增强,如日志切面就是一个横切关注点,应用中许多方法需要做日志记录的只需要插入日志的切面即可。这种面向切面编程的思想就是AOP思想了。
1.2 AOP的功能
AOP能够将那些与Service业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
1.3 AOP当中的概念
Joinpoint:连接点,被拦截到需要被增强的方法。where:去哪里做增强
Pointcut:切入点,哪些包中的哪些类中的哪些方法,可认为是连接点的集合。where:去哪些地方做增强
Advice:增强,当拦截到Joinpoint之后,在方法执行的什么时机(when)做什么样(what)的增强。
Aspect:切面,Pointcut+Advice,去哪些地方+在什么时候+做什么增强
Weaving:织入,把Advice加到Target上之后,创建出Proxy对象的过程。
注意:
Spring的AOP使用动态代理实现:
如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;
如果一个类没有实现接口,那么spring就是用cglib完成AOP;
1.4 Pointcut语法:
切入点一般指业务类
- AspectJ切入点语法如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?) - 翻译成中文:
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?) - 举例:public static Class java.lang.Class.forName(String className)throws ClassNotFoundException
- 通配符:
*:匹配任何部分,只能表示一个单词
… 可用于全限定名中和方法参数中,分别表示子包和0到N个参数
1.4 AOP实现方式
(1)xml编程实现
(2)注解实现
2、xml编程实现
(1)创建Service层和Dao层
定义好业务层和dao代码
public class UserServiceImpl implements IUserService {
@Setter
private IUserDao dao;
@Override
public void save() {
dao.save();
}
@Override
public void update() {
dao.update();
}
}
(2)创建事务类
获取增强函数
JoinPoint :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。
ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。
public class BusManager {
public void begin(JoinPoint jp){
System.out.println("开启事务...");
/*JoinPoint :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。*/
/*获取被代理的对象(房间主人)*/
System.out.println(jp.getTarget().getClass());
/*获取代理对象(中介)*/
System.out.println(jp.getThis().getClass());
/*获取被增强方法的参数,(接口方法)*/
System.out.println(jp.getSignature());
/*获取传入目标方法的参数对象*/
System.out.println(Arrays.toString(jp.getArgs()));
}
public void commit(){
System.out.println("提交事务...");
}
/*通过xml文件配置增强标签,可以捕获异常信息,在这里打印*/
public void rollback(Exception ex)
{
System.out.println("回滚事务...");
System.out.println(ex);
}
public void destory(){
System.out.println("释放资源...");
}
/*环绕方法,自定义逻辑。*/
public Object around(ProceedingJoinPoint pjp){
/*ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。 */
Object res = null;
try{
System.out.println("开启事务");
//执行被增强的方法
res = pjp.proceed();
System.out.println("提交事务");
}catch (Throwable e){
System.out.println("回滚事务");
e.printStackTrace();
}finally {
System.out.println("释放资源");
}
return res;
}
}
(3)Spring AOP开发依赖的jar:(除基础依赖之外)
spring-aop-4.1.2.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring5开始在spring-aop库中纳入了AOP联盟的API,不再需要拷贝aopalliance-1.0.0.jar。
<project.spring.version>5.0.0.RELEASE</project.spring.version>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${project.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${project.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${project.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${project.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${project.spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${project.spring.version}</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--Aop依赖之一-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
(4)配置aop命名空间:
(5)配置文件中添加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="ser" class="com.project.AOP4xml.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="com.project.AOP4xml.dao.impl.UserDaoImpl" />
<bean id="busmanager" class="com.project.AOP4xml.business.BusManager"/>
<!--配置aop,底层是动态代理proxy-->
<aop:config>
<!--
pointcut:切入点:
哪些包里的那些类中的那些方法,需要被增强(where)
execution(<访问修饰符>? <返回类型> <声明类型>? <方法名>(<参数>) <异常>?)
?可以被省略
-->
<aop:pointcut id="pc" expression="execution( * com.project.AOP4xml.service.IUserService.*(..))"/>
<!--
配置切面:
Aspect = pointcut+Advice(when+what) 切面 = 切入点+增强
-->
<aop:aspect ref="busmanager">
<!-- 前置增强,在执行业务方法之前要执行的方法-->
<aop:before method="begin" pointcut-ref="pc"/>
<!--后置增强,在执行业务方法之后要执行的方法-->
<aop:after-returning method="commit" pointcut-ref="pc"/>
<!--异常增强,执行业务方式时,出错要执行的的方法 通过throwing标签捕获异常-->
<aop:after-throwing method="rollback" pointcut-ref="pc" throwing="ex"/>
<!--最终增强,无论业务方式能否执行,都会执行的方法-->
<aop:after method="destory" pointcut-ref="pc"/>
<!--环绕方法,自定义逻辑-->
<!--<aop:around method="around" pointcut-ref="pc"/>-->
</aop:aspect>
</aop:config>
</beans>
(6)测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestRun {
@Autowired
private IUserService usi;
@Test
public void run(){
usi.save();
}
@Test
public void run1(){
usi.update();
}
}
3、注解实现
在xml实现的基础上,修改为注解实现AOP
(1)添加AOP的注解解析器:
在xml配置文件中,添加AOP的注解解析器:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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="service" class="com.project.AOP4anno.service.impl.UserServiceImpl">
<property name="dao" ref="dao"/>
</bean>
<bean id="dao" class="com.project.AOP4anno.dao.impl.UserDaoImpl" />
<bean id="busmanager" class="com.project.AOP4anno.business.BusManager"/>
<!--添加AoP注解解析器-->
<aop:aspectj-autoproxy/>
</beans>
(2)修改事务类
1、在事务控制的类中添加@Aspect注解
2、在类中新建任意无参数无返回的方法,为方法添加注解"@Pointcut",注解的value值为execution表达式.方法名为Pointcut的id;
3、事务控制的方法添加各自增强时机的注解.
@Before:前置增强
@AfterReturning:后置增强
@AfterThrowing:异常增强,标签写法与其他有区别
@After:最终增强
@Around:环绕增强
各个注解的value值为Pointcut的id.
package com.project.AOP4anno.business;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import java.util.Arrays;
@Aspect
public class BusManager {
@Pointcut("execution( * com.project.AOP4anno.service.IUserService.*(..))")
public void bm(){
}
@Before("bm()")
public void begin(JoinPoint jp){
System.out.println("开启事务...");
/*JoinPoint :提供访问当前被增强方法的真实对象、代理对象、方法参数等数据。*/
/*获取被代理的对象(房间主人)*/
System.out.println(jp.getTarget().getClass());
/*获取代理对象(中介)*/
System.out.println(jp.getThis().getClass());
/*获取被增强方法的参数,(接口方法)*/
System.out.println(jp.getSignature());
/*获取传入目标方法的参数对象*/
System.out.println(Arrays.toString(jp.getArgs()));
}
@After("bm()")
public void commit(){
System.out.println("提交事务...");
}
/*通过xml文件配置增强标签,可以捕获异常信息,在这里打印*/
@AfterThrowing(value = "bm()",throwing = "ex")
public void rollback(Exception ex)
{
System.out.println("回滚事务...");
System.out.println(ex);
}
@After("bm()")
public void destory(){
System.out.println("释放资源...");
}
/*环绕方法,自定义逻辑。*/
/*@Around("bm()")*/
public Object around(ProceedingJoinPoint pjp){
/*ProceedingJoinPoint:JinPoint子类,只用于环绕增强中,可以处理被增强方法。 */
Object res = null;
try{
System.out.println("开启事务");
//执行被增强的方法
res = pjp.proceed();
System.out.println("提交事务");
}catch (Throwable e){
System.out.println("回滚事务");
e.printStackTrace();
}finally {
System.out.println("释放资源");
}
return res;
}
}
(3)测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestRun {
@Autowired
private IUserService service;
@Test
public void run(){
service.save();
}
@Test
public void run1(){
service.update();
}
}