Spring 04 -SpringAOP开发
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{@Overridepublic 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 返回的是该方法的返回值*/@Overridepublic 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*/@Overridepublic 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 {@Autowiredprivate UserService userService;@Testpublic 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 {@Autowiredprivate UserService userService;@Testpublic void test01(){userService.deleteUser();}
}
结果
前置通知(在目标对象的方法之前执行)
deleteUser...
后置通知(在目标对象的方法之后执行(如果有异常则不会执行))
最终通知(在目标对象的方法之后执行(有没有异常都会执行))
2.5 通知类型
- 环绕通知
public Object around(ProceedingJoinPoint joinPoint){}
- 调用目标对象的方法
joinPoint.proceed();
- 四种通知:
- 前置通知【在调用目标方法之前执行】(开启事务)
- 最终通知【在调用目标方法之后执行(无论是否有错都会执行)】(释放资源)
- 异常通知【在调用目标方法报错执行】(回滚事务)
- 后置通知【在调用目标方法之后执行】(提交事务)