当前位置: 首页 > news >正文

SpringAOP详解(上)

当需要在方法前后做一些操作就需要借助动态代理来实现

一、动态代理实现方法

1、jdk自带实现方式

jdk实现代理是被代理类实现接口的方式

public interface UserInterface {void test();
}public class UserService implements UserInterface {public void test() {System.out.println("call test method");}}UserService target = new UserService();Object o = Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("test method before");Object invoke = method.invoke(target, args);System.out.println("test method after");return invoke;}});// 只能代理实现UserInterface接口的类,不能强转成UserServiceUserInterface userInterface = (UserInterface)o;userInterface.test();

打印结果:

test method before
call test method
test method after 

必须基于实现接口,产生代理对象类型是UserInterface,而不是UserService

2、基于cglib实现

相比jdk动态代理,cglib不需要修改代码就可以实现动态代理,cglib实现代理是继承被代理类的方式

public class UserService {public void test() {System.out.println("call test method");}public void a() {System.out.println("call test a");}
}UserService target = new UserService();// 通过cglib技术Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);// 定义额外逻辑,也就是代理逻辑enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before...");Object result = methodProxy.invoke(target, objects);System.out.println("after...");return result;}}, NoOp.INSTANCE});enhancer.setCallbackFilter(new CallbackFilter() {@Overridepublic int accept(Method method) {if (method.getName().equals("test")) {return 0;} else {return 1;}}});// 动态代理所创建出来的UserService对象UserService userService = (UserService) enhancer.create();// 执行这个userService的test方法时,就会额外会执行一些其他逻辑userService.test();// 调用a方法时对应过滤返回的是1,NoOp.INSTANCE是空操作,不会对代理对象做任何操作userService.a();

打印结果:

before...
call test method
after...
call test a

3、spring对jdk和cglib进行封装的ProxyFactory

public class UserService {public void test() {System.out.println("call test method");}
}UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置proxyFactory.addAdvice(new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});UserService userService = (UserService) proxyFactory.getProxy();userService.test();

打印结果:

before...
call test method
after...

4、Advice分类

  1. Before Advice:方法之前执行
  2. After returning advice:方法return后执行
  3. After throwing advice:方法抛异常后执行
  4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后
  5. Around advice:这是功能最强大的Advice,可以自定义执行顺序
Before Advice
ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置proxyFactory.addAdvice(new TestBeforeAdvice());UserService userService = (UserService) proxyFactory.getProxy();userService.test();public class TestBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("方法执行之前");}
}public class UserService {public void test() {System.out.println("call test method");}
}

打印结果:

方法执行之前
call test method 

After returning advice
ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置proxyFactory.addAdvice(new TestAfterReturningAdvice());UserService userService = (UserService) proxyFactory.getProxy();userService.test();public class TestAfterReturningAdvice implements AfterReturningAdvice {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("方法返回之后");}
}public class UserService {public void test() {System.out.println("call test method");}
}

打印结果:

call test method
方法返回之后 

After throwing advice

可根据异常类型在指定异常发生时做对应操作

ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置proxyFactory.addAdvice(new TestAfterThrowingAdvice());UserService userService = (UserService) proxyFactory.getProxy();userService.test();public class TestAfterThrowingAdvice implements ThrowsAdvice {public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {System.out.println("方法执行发生异常");}
}public class UserService {public void test() {System.out.println("call test method");throw new RuntimeException();}
}

打印结果:

call test method
方法执行发生异常
Exception in thread "main" java.lang.RuntimeExceptionat com.zhouyu.service.UserService.test(UserService.java:25)at com.zhouyu.service.UserService$$FastClassBySpringCGLIB$$7bfcfe0.invoke(<generated>)at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:791)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:166)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:113)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:198)at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762)at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704)at com.zhouyu.service.UserService$$EnhancerBySpringCGLIB$$e9a0fc71.test(<generated>)at com.zhouyu.Test.main(Test.java:25)
Around advice:
UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置proxyFactory.addAdvice(new TestAroundAdvice());UserService userService = (UserService) proxyFactory.getProxy();userService.test();public class UserService {public void test() {System.out.println("call test method");}
}public class TestAroundAdvice implements MethodInterceptor {@Nullable@Overridepublic Object invoke(@NotNull MethodInvocation invocation) throws Throwable {System.out.println("方法执行之前");Object proceed = invocation.proceed();System.out.println("方法执行之后");return proceed;}
}

打印结果:

方法执行之前
call test method
方法执行之后

上述的Advice只要是UserService类的方法都会被代理执行

5、Advisor

添加自己想执行的执行的方法,下面代码只会执行test方法的Advice代码

public class UserService {public void test() {System.out.println("call test method");}public void a() {System.out.println("call test a");}
}UserService target = new UserService();ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(target);
//		proxyFactory.setInterfaces(UserInterface.class); // jdk动态时设置
//		proxyFactory.addAdvice(new TestBeforeAdvice());proxyFactory.addAdvisor(new PointcutAdvisor() {@Overridepublic Pointcut getPointcut() {return new StaticMethodMatcherPointcut() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {if (method.getName().equals("test")) {return true;}return false;}};}@Overridepublic Advice getAdvice() {return new TestBeforeAdvice();}@Overridepublic boolean isPerInstance() {return false;}});UserService userService = (UserService) proxyFactory.getProxy();userService.test();userService.a();

打印结果:

方法执行之前
call test method
call test a

二、ProxyFactoryBean

利用ProxyFactoryBean生成一个代理对象,执行test方法之前执行代理逻辑

public class UserService {public void test() {System.out.println("call test method");}public void a() {System.out.println("call test a");}
}@Beanpublic ProxyFactoryBean userServiceProxy() {ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();proxyFactoryBean.setTarget(new UserService());proxyFactoryBean.addAdvice(new TestBeforeAdvice());return proxyFactoryBean;}AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userServiceProxy");userService.test();

打印结果:

方法执行之前
call test method 

三、BeanNameAutoProxyCreator

beanName匹配到的将会自动创建代理对象,根据设置的Advice在调用方法时执行相关代理逻辑(通过beanPostProcessor把Advice添加到一个集合中,当调用调用被代理类时,指定的beanName的方法执行时都会执行代理逻辑)

@Beanpublic BeanNameAutoProxyCreator beanNameAutoProxyCreator() {BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();beanNameAutoProxyCreator.setBeanNames("userSe*");beanNameAutoProxyCreator.setInterceptorNames("testBeforeAdvice");beanNameAutoProxyCreator.setProxyTargetClass(true);return beanNameAutoProxyCreator;}@Component
public class TestBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("方法执行之前");}
}AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.test();

打印结果:

方法执行之前
call test method

四、DefaultAdvisorAutoProxyCreator

// 定义一个advisor@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor(){NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("test");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(new TestBeforeAdvice());return defaultPointcutAdvisor;}// 执行beanPostProcessor时会把advisor添加到一个集合中@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();return defaultAdvisorAutoProxyCreator;}AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) applicationContext.getBean("userService");userService.test();

打印结果:

方法执行之前
call test method

五、AOP概念

AspectJ是在编译时对字节码进行了修改,是直接在UserService类对应的字节码中进行增强的,也就是可以理解为是在编译时就会去解析@Before这些注解,然后得到代理逻辑,加入到被代理的类中的字节码中去的,所以如果想用AspectJ技术来生成代理对象 ,是需要用单独的AspectJ编译器的。我们在项目中很少这么用,我们仅仅只是用了@Before这些注解,而我们在启动Spring的过程中,Spring会去解析这些注解,然后利用动态代理机制生成代理对象的。

  1. Aspect:表示切面,比如被@Aspect注解的类就是切面,可以在切面中去定义Pointcut、Advice等等
  2. Join point:表示连接点,表示一个程序在执行过程中的一个点,比如一个方法的执行,比如一个异常的处理,在Spring AOP中,一个连接点通常表示一个方法的执行。
  3. Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型,后面详细讨论,在很多AOP框架中,包括Spring,会用Interceptor拦截器来实现Advice,并且在连接点周围维护一个Interceptor链
  4. Pointcut:表示切点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上
  5. Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现
  6. Target object:目标对象,被代理对象
  7. AOP proxy:表示代理工厂,用来创建代理对象的,在Spring Framework中,要么是JDK动态代理,要么是CGLIB代理
  8. Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP

​AspectJ定义的几个注解

  1. @Before
  2. @AfterReturning
  3. @AfterThrowing
  4. @After
  5. @Around
http://www.lryc.cn/news/143106.html

相关文章:

  • C++ 存储类
  • 【教程分享】Docker搭建Zipkin,实现数据持久化到MySQL、ES
  • 数据库——MySQL高性能优化规范
  • openapi中job提交
  • Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 数据聚合
  • 深入探讨代理技术:保障网络安全与爬虫效率
  • 【云原生】Docker私有仓库 RegistryHabor
  • 二叉树先序遍历的两种思路
  • 小研究 - JVM 逃逸技术与 JRE 漏洞挖掘研究(一)
  • 好用的可视化大屏适配方案
  • 言有三新书出版,《深度学习之图像识别(全彩版)》上市发行,配套超详细的原理讲解与丰富的实战案例!...
  • 英特尔开始加码封装领域 | 百能云芯
  • 基于大数据+django+mysql的学习资源推送系统的设计与实现(含报告+源码+指导)
  • CCF HPC China2023 | 盛大开幕,邀您关注澎峰科技
  • 【git进阶使用】 告别只会git clone 学会版本控制 ignore筛选 merge冲突等进阶操作
  • 【【萌新的STM32学习-16中断的基本介绍1】】
  • ctfshow-红包题第二弹
  • C# winform中无标题栏窗口如何实现鼠标拖动?
  • 【操作系统】各平台定时器粒度
  • 抽象又有点垃圾的JavaScript
  • 【Spring Boot】使用Spring Boot进行transformer的部署与开发
  • Qt应用开发(基础篇)——富文本浏览器 QTextBrowser
  • JDBC:更新数据库
  • 如何自定义iview树形下拉内的内容
  • 技术的巅峰演进:深入解析算力网络的多层次技术设计
  • 图像特征描述和人脸识别
  • 浅谈Lua协程和函数的尾调用
  • 【VS Code插件开发】状态栏(五)
  • 睿趣科技:抖音开网店要怎么找货源
  • 表和Json的相互操作