Spring-AOP
SpringAOP简介
优势及其作用
Aop的底层实现
Aop的动态代理技术
基于jdk的动态代理
package cn.zhw.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
Target target = new Target();
Advice advice = new Advice();
//返回动态代理的代理对象,必须用接口接受
TargetInter o = (TargetInter) Proxy.newProxyInstance(
target.getClass().getClassLoader(), //目标对象的加载器
target.getClass().getInterfaces(),//目标对象的接口字节码对象数组
new InvocationHandler() {
//调用代理对象的任何方法,实质执行的都是invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置增强方法
advice.before();
//获取方法名字
String name = method.getName();
System.out.println(name);
//method为代理对象调用的方法
Object invoke = method.invoke(target, args);
//打印方法的参数
for (Object arg : args) {
System.out.println(arg);
}
//后置增强方法
advice.after();
return null;
}
}
);
//执行代理对象的方法
o.save(56);
System.out.println("=====");
o.update("zhw","henan");
}
}
结果
前置增强
save 方法名
56 参数
后置增强
=====
前置增强
update 方法名
zhw 参数
henan 参数
后置增强
当执行代理对象的中的方法,会接受其中的参数给invoke方法的args数组里面,把方法给invoke的method参数,每一次执行代理对象那个的方法,其实就是执行的invoke方法
package cn.zhw.proxy.jdk;
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
@Test
public void test1(){
Target target = new Target();
Advice advice = new Advice();
TargetInter proxy = (TargetInter) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before();
String name = method.getName();
if("save".equals(name)){
method.invoke(target,args);
}else {
System.out.println("不是save方法");
}
advice.after();
return null;
}
}
);
proxy.update("zhw","kaifeng");
}
}
前置增强
不是save方法
后置增强
基于cglib的动态代理
package cn.zhw.proxy.cglib;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author 小七
* 测试cglib动态代理
*/
public class ProxyTest {
@Test
public void test(){
Target target = new Target(); //创建目标对象
Advice advice = new Advice(); //创建切面类
Enhancer enhancer = new Enhancer(); //创建增强器
enhancer.setSuperclass(Target.class); //设置父类
enhancer.setCallback(new MethodInterceptor() { //设置回调
/**
* @param method 目标方法
* @param objects 方法的参数
*/
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
//前置增强
advice.before();
Object invoke = method.invoke(target, objects);
//后置增强
advice.after();
return invoke;
}});
Target proxy = (Target) enhancer.create(); //创建代理对象
proxy.update("zhw","henan"); //执行代理对象的方法
}
}
前置增强
zhw:henan
后置增强
AOP相关概念
AOP开发明确的事项
快速入门
1.引入坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- aspectj的织入比spring原生的aop实现效率高 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
2.创建目标接口和目标类
目标类接口
package cn.zhw.aop.service;
/**
* @author 小七
* @date 2022/7/4
* @time 7:27
*/
public interface LogService {
public void pringDate(String name);
}
目标类
package cn.zhw.aop.service.impl;
import cn.zhw.aop.service.LogService;
import org.springframework.stereotype.Service;
/**
* @author 小七
* @date 2022/7/4
* @time 7:27
*/
@Service
public class LogServiceImpl implements LogService {
@Override
public void pringDate(String name) {
System.out.println(name);
// throw new IndexOutOfBoundsException("我故意抛出的异常");
}
}
3.创建切面类
package cn.zhw.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @author 小七
* @date 2022/7/4
* @time 7:26
*/
public class LogAspect {
// 前置通知
public void before(JoinPoint joinPoint) throws Throwable {
System.out.println("LogAspect的前置通知");
Object[] args = joinPoint.getArgs();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < args.length; i++) {
stringBuilder.append(args[i]);
}
// System.out.println("获取的参数为:"+args[0]);
System.out.println("LogAspect的前置通知执行完成");
}
// 最终通知:无论是否出现异常都会执行
public void after(JoinPoint joinPoint) throws Throwable {
System.out.println("LogAspect的最终通知");
System.out.println("LogAspect的最终通知执行完成");
}
// 环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
joinPoint.proceed(joinPoint.getArgs());
System.out.println("环绕通知后");
}
// 后置通知:指定的增强的方法执行后才执行
public void returning(JoinPoint joinPoint) throws Throwable {
System.out.println("后置通知");
System.out.println("后置通知完成");
}
public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
System.out.println("出现异常");
System.out.println("异常信息为:"+e.getMessage());
}
}
4.将目标类和切面类交给spring容器管理
<!-- 配置目标类-->
<bean id="target" class="cn.zhw.proxy.cglib.Target"/>
<!-- 配置切面类-->
<bean id="myAspect" class="cn.zhw.proxy.cglib.MyAspect"/>
5.引入Aop命名空间,配置织入关系
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- aop配置,xml配置-->
<bean id="myAdvice" class="cn.zhw.aop.aspect.LogAspect"/>
<bean id="logService" class="cn.zhw.aop.service.impl.LogServiceImpl"/>
<aop:config>
<!-- 全局接入点-->
<aop:pointcut id="pointcut" expression="execution(* cn.zhw.aop.service.impl.LogServiceImpl.*(..))"/>
<!-- 配置aop-->
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="returning" pointcut-ref="pointcut"/>
<!-- 将抛出的错误给参数e-->
<aop:after-throwing method="throwing" pointcut-ref="pointcut" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>
6.测试
package cn.zhw.aop;
import cn.zhw.aop.service.LogService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.PriorityQueue;
/**
* @author 小七
* @date 2022/7/4
* @time 14:08
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private ApplicationContext app;
@Autowired
private LogService logService;
@Test
public void test1(){
this.logService.pringDate("LogService的方法执行了");
}
}
7.结果
LogAspect的前置通知
LogAspect的前置通知执行完成
环绕通知前
LogService的方法执行了
后置通知
后置通知完成
环绕通知后
LogAspect的最终通知
LogAspect的最终通知执行完成
切点表达式写法
execution(* *..*.*(..))
表示 任意返回类型 所有包 所有类 所有方法 所有的参数
通知的类型
1.通知的类型以及使用
package cn.zhw.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @author 小七
* @date 2022/7/4
* @time 7:26
*/
public class LogAspect {
// 前置通知
public void before(JoinPoint joinPoint) throws Throwable {
System.out.println("LogAspect的前置通知");
Object[] args = joinPoint.getArgs();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < args.length; i++) {
stringBuilder.append(args[i]);
}
// System.out.println("获取的参数为:"+args[0]);
System.out.println("LogAspect的前置通知执行完成");
}
// 最终通知:无论是否出现异常都会执行
public void after(JoinPoint joinPoint) throws Throwable {
System.out.println("LogAspect的最终通知");
System.out.println("LogAspect的最终通知执行完成");
}
// 环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕通知前");
joinPoint.proceed(joinPoint.getArgs());
System.out.println("环绕通知后");
}
// 后置通知:指定的增强的方法执行后才执行
public void returning(JoinPoint joinPoint) throws Throwable {
System.out.println("后置通知");
System.out.println("后置通知完成");
}
// 异常通知:目标方法执行的时间出现异常,才会执行本方法,并将exception给参数e
public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
System.out.println("出现异常");
System.out.println("异常信息为:"+e.getMessage());
}
}
2.配置增强
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!-- aop配置,xml配置-->
<bean id="myAdvice" class="cn.zhw.aop.aspect.LogAspect"/>
<bean id="logService" class="cn.zhw.aop.service.impl.LogServiceImpl"/>
<aop:config>
<!-- 全局接入点-->
<aop:pointcut id="pointcut" expression="execution(* cn.zhw.aop.service.impl.LogServiceImpl.*(..))"/>
<!-- 配置aop-->
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:around method="around" pointcut-ref="pointcut"/>
<aop:after-returning method="returning" pointcut-ref="pointcut"/>
<!-- 将抛出的错误给参数e-->
<aop:after-throwing method="throwing" pointcut-ref="pointcut" throwing="e"/>
</aop:aspect>
</aop:config>
</beans>
AOP注解开发
1.目标类
package cn.zhw.aop.service.impl;
import cn.zhw.aop.service.LogService;
import org.springframework.stereotype.Service;
/**
* @author 小七
* @date 2022/7/4
* @time 7:27
*/
@Service
public class LogServiceImpl implements LogService {
@Override
public void pringDate(String name) {
System.out.println(name);
// throw new IndexOutOfBoundsException("我故意抛出的异常");
}
}
2.切面类
package cn.zhw.aop.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.Commit;
/**
* @author 小七
* @date 2022/7/4
* @time 7:26
*/
@Component
@Aspect
public class AnnotationAspect {
@Pointcut("execution(* cn.zhw.aop.service.impl.LogServiceImpl.*(..))")
public void pointcut(){};
@Before("pointcut()")
// 前置通知
public void before(JoinPoint joinPoint) throws Throwable {
System.out.println("AnnotationAspect的前置通知");
System.out.println("AnnotationAspect的前置通知执行完成");
}
// 最终通知:无论是否出现异常都会执行
@After("pointcut()")
public void after(JoinPoint joinPoint) throws Throwable {
System.out.println("AnnotationAspect的最终通知");
System.out.println("AnnotationAspect的最终通知执行完成");
}
// 环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
@Around("pointcut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AnnotationAspect环绕通知前");
joinPoint.proceed(joinPoint.getArgs());
System.out.println("AnnotationAspect环绕通知后");
}
// 后置通知:指定的增强的方法执行后才执行
@AfterReturning("pointcut()")
public void returning(JoinPoint joinPoint) throws Throwable {
System.out.println("AnnotationAspect后置通知");
System.out.println("AnnotationAspect后置通知完成");
}
@AfterThrowing(value = "pointcut()",throwing = "e")
public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
System.out.println("AnnotationAspect出现异常");
System.out.println("异常信息为:"+e.getMessage());
}
}
3.配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 注解版配置
1.使用包扫描把bean注册进来
2.开启aop自动代理
3.编写切面类
-->
<aop:aspectj-autoproxy/>-->
<context:component-scan base-package="cn.zhw.aop">
</context:component-scan>
</beans>
4.测试
package cn.zhw.aop;
import cn.zhw.aop.service.LogService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.PriorityQueue;
/**
* @author 小七
* @date 2022/7/4
* @time 14:08
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private ApplicationContext app;
@Autowired
private LogService logService;
@Test
public void test1(){
this.logService.pringDate("LogService的方法执行了");
}
}