SpringAOP开发
- SpringAOP
- 1 原理
- 2 动态代理
- 2.1 JDK动态代理
- 2.2.2 Cglib动态代理
- 2.2.3 **JDK动态代理和Cglib动态代理**
- 3 SpringAOP
- 3.1 AOP专业术语
- 3.2 环境搭建
- 3.3 基于XML配置
- 3.4 基于注解配置
- 2.5 通知类型
面向切面编程,在不修改源代码的情况加,对类功能实现增强
SpringAOP
1 原理
AOP原理 |
---|
2 动态代理
Spring的底层技术就是动态代理
- 动态代理分类
- JDK动态代理
- Cglib动态代理
2.1 JDK动态代理
接口:定义代理对象和被代理对象需要做的事情
//定义代理类和被代理类共同做的事情
public interface Subject {
void saleHouse();
}
实现类:目标对象(被增强对象)
public class RealSubject implements Subject{
@Override
public void saleHouse() {
System.out.println("买房子....");
}
}
代理工厂
public class JDKProxyFactory {
/**
* 使用jdk动态代理,获取代理对象
* @param obj 被代理对象
* @return 代理对象
*/
public static Object getProxy(Object obj){
//类加载器
ClassLoader classLoader = JDKProxyFactory.class.getClassLoader();
//被代理对象所实现的接口
Class<?>[] interfaces = obj.getClass().getInterfaces();
//对对象的方法调用的拦截
InvocationHandler invocationHandler = new InvocationHandler() {
/**
*
* @param proxy 代理对象
* @param method 拦截方法
* @param args 拦截方法的参数
* @return 返回的是该方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//做增强工作
System.out.println("找客户。。。。");
Object invoke = method.invoke(obj, args);
System.out.println("办手续。。。。");
return invoke;
}
};
Object proxyInstance =
Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxyInstance;
}
}
测试
@Test
public void test01(){
//通过代理工厂获取代理对象,通过代理对象调用方法
Subject proxy = (Subject) JDKProxyFactory.getProxy(new RealSubject());
proxy.saleHouse();
//说明代理对象不属于RealSubject类,而是Subject接口的实现类
System.out.println(proxy instanceof RealSubject); //false
}
2.2.2 Cglib动态代理
类:目标对象(被增强对象) 不需要实现接口
public class RealSubject{
public void saleHouse() {
System.out.println("买房子....");
}
}
动态代理工厂
public class CglibProxyFactory {
public static Object getProxy(Object obj){
//创建Cglib代理工具类对象
Enhancer enhancer = new Enhancer();
//设置代理对象的父类(代理对象和被代理对象是继承关系)
enhancer.setSuperclass(obj.getClass());
Callback callback = new MethodInterceptor() {
/**
*
* @param o 代理对象
* @param method 拦截的方法
* @param objects 拦截的方法参数
* @param methodProxy 方法的代理对象
* @return 方法的返回值
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
//做增强工作
System.out.println("找客户cglib。。。。");
Object invoke = method.invoke(obj, objects);
System.out.println("办手续cglib。。。。");
return invoke;
}
};
//拦截被代理对象的方法
enhancer.setCallback(callback);
//创建代理对象
Object o = enhancer.create();
return o ;
}
}
测试
@Test
public void test02(){
//被代理对象
RealSubject realSubject = new RealSubject();
//通过代理工厂获取代理对象,通过代理对象调用方法
//代理对象
RealSubject proxy = (RealSubject) CglibProxyFactory.getProxy(realSubject);
proxy.saleHouse();
//说明代理对象属于RealSubject类,而且就是RealSubject类的子类
System.out.println(proxy instanceof RealSubject); //true
}
2.2.3 JDK动态代理和Cglib动态代理
JDK动态代理和Cglib动态代理
- 两者都可以实现产生代理对象
- JDK动态代理是java原生自带的,Cglib动态代理是第三方的
- JDK动态代理实现代理:代理对象和目标对象之间实现同一个接口
- Cglib动态代理实现代理:代理对象是目标对象的子类
3 SpringAOP
3.1 AOP专业术语
- 连接点(Joinpoint): 表示一切能被增强方法
- 切入点(Pointcut): 被增强的方法
<aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/>
- 通知、增强(Advice): 增强的功能(通知的类型:前置通知、后置通知、异常通知、最终通知、环绕通知) <
aop:before method="before" pointcut-ref="pc"/>
- 目标对象(Target): 被代理对象
- 织入(Weaving): 将通知加入连接点的过程
aop:aspect ref=""
里面的代码过程- 代理(Proxy): 代理对象
- 切面(Aspect): 连接点被增强的内容称之为切面(切入点+通知)
aop:aspect ref=""
3.2 环境搭建
导入依赖
spring-aspects
<!-- springAOP切面开发的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.6</version>
</dependency>
3.3 基于XML配置
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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.ying.aop"/>
<!-- SpringAOP的配置 -->
<!-- 创建增强类 -->
<bean id="advice" class="com.ying.advice.MyAdvice"></bean>
<aop:config>
<!-- SpringAOP的切面 -->
<aop:aspect ref="advice">
<!-- SpringAOP切入点 id:切入点的唯一标识 expression:切入点表达式 -->
<!--
切入点表达式
方法的全称
public void com.ying.service.impl.UserServiceImpl.addUser();
* com.ying.service.impl.UserServiceImpl.addUser();
* com.ying.service..*.*(..);
* com.ying.service.*.*Impl.*();
-->
<aop:pointcut id="pc" expression="execution(* com.ying.service..*.*(..))"/>
<!-- SpringAOP的通知配置 -->
<!-- <aop:before method="before" pointcut-ref="pc"></aop:before>-->
<!-- <aop:after method="after" pointcut-ref="pc"></aop:after>-->
<!-- <aop:after-throwing method="throwing" pointcut-ref="pc"/>-->
<!-- <aop:after-returning method="returning" pointcut-ref="pc"/>-->
<aop:around method="around" pointcut-ref="pc"></aop:around>
</aop:aspect>
</aop:config>
</beans>
增强(通知)类
//增强类
public class MyAdvice {
// public void before(){
// System.out.println("前置通知(在目标对象的方法之前执行)");
// }
// public void after(){
// System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
// }
// public void throwing(){
// System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
// }
// public void returning(){
// System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
// }
public Object around(ProceedingJoinPoint joinPoint){
try {
System.out.println("前置通知(在目标对象的方法之前执行)");
//System.out.println("方法本身");
//执行目标对象的方法
Object o = joinPoint.proceed();
//获取到目标对象
Object target = joinPoint.getTarget();
System.out.println(target);
//获取目标对象的方法
Signature signature = joinPoint.getSignature();
System.out.println(signature.getName());
System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
//通过调用目标对象的方法获取到返回值,并继续返回
return o;
} catch (Throwable e) {
e.printStackTrace();
System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
} finally {
System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
}
return null;
}
}
测试 依赖
spring-test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AOPTest {
@Autowired
private UserService userService;
@Test
public void test01(){
int count = userService.addUser();
System.out.println(count);
//userService.deleteUser();
}
}
结果
前置通知(在目标对象的方法之前执行)
addUser...
com.ying.service.impl.UserServiceImpl@543588e6
addUser
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))
100
3.4 基于注解配置
xml配置文件
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.ying"/>
<!-- 开启AOP的注解扫描 -->
<aop:aspectj-autoproxy/>
增强类
@Component
@Aspect //设置为切面
public class MyAdvice2 {
@Pointcut("execution(* com.ying.service..*.*(..))")
public void pc(){}
@Before("pc()")
public void before(){
System.out.println("前置通知(在目标对象的方法之前执行)");
}
@After("execution(* com.ying.service..*.*(..))")
public void after(){
System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
}
@AfterThrowing("execution(* com.ying.service..*.*(..))")
public void throwing(){
System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
}
@AfterReturning("execution(* com.ying.service..*.*(..))")
public void returning(){
System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
}
// @Around("execution(* com.ying.service..*.*(..))")
// public Object around(ProceedingJoinPoint joinPoint){
// try {
// System.out.println("前置通知(在目标对象的方法之前执行)");
// //System.out.println("方法本身");
// //执行目标对象的方法
// Object o = joinPoint.proceed();
// //获取到目标对象
// Object target = joinPoint.getTarget();
// System.out.println(target);
// //获取目标对象的方法
// Signature signature = joinPoint.getSignature();
// System.out.println(signature.getName());
// System.out.println("后置通知(在目标对象的方法之后执行(如果有异常则不会执行))");
// //通过调用目标对象的方法获取到返回值,并继续返回
// return o;
// } catch (Throwable e) {
// e.printStackTrace();
// System.out.println("异常通知(在目标对象的方法之后执行(如果有异常则才会执行))");
// } finally {
// System.out.println("最终通知(在目标对象的方法之后执行(有没有异常都会执行))");
// }
// return null;
// }
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class AOPTest {
@Autowired
private UserService userService;
@Test
public void test01(){
userService.deleteUser();
}
}
结果
前置通知(在目标对象的方法之前执行)
deleteUser...
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))
2.5 通知类型
- 环绕通知
public Object around(ProceedingJoinPoint joinPoint){}
- 调用目标对象的方法
joinPoint.proceed();
- 四种通知:
- 前置通知【在调用目标方法之前执行】(开启事务)
- 最终通知【在调用目标方法之后执行(无论是否有错都会执行)】(释放资源)
- 异常通知【在调用目标方法报错执行】(回滚事务)
- 后置通知【在调用目标方法之后执行】(提交事务)