手写Spring:第12章-基于JDK、Cglib实现AOP切面

文章目录

  • 一、目标:基于JDK、Cglib实现AOP切面
  • 二、设计:基于JDK、Cglib实现AOP切面
  • 三、实现:基于JDK、Cglib实现AOP切面
    • 3.0 引入依赖
    • 3.1 工程结构
    • 3.2 AOP切点表达式和使用以及基于JDK和CGLIB的动态代理类图
    • 3.3 切点表达式
      • 3.3.1 类匹配接口
      • 3.3.2 匹配方法接口
      • 3.3.3 切点表达式接口
      • 3.3.4 实现切点表达式类
    • 3.4 包装切面通知信息
      • 3.4.1 被代理的目标对象
      • 3.4.2 包装切面通知消息
    • 3.5 代理抽象实现(JDK&Cglib)
      • 3.5.1 反射方法调用
      • 3.5.2 AOP代理接口
      • 3.5.3 JDK 动态代理
      • 3.5.4 Cglib代理
  • 四、测试:基于JDK、Cglib实现AOP切面
    • 4.1 添加测试配置
      • 4.1.1 用户接口
      • 4.1.2 用户接口实现类
      • 4.1.3 自定义用户拦截方法
    • 4.2 单元测试
      • 4.2.1 代理方法测试
      • 4.2.2 匹配方法测试
      • 4.2.3 单元测试
  • 五、总结:基于JDK、Cglib实现AOP切面

一、目标:基于JDK、Cglib实现AOP切面

💡 AOP是什么?如何实现AOP?

  • AOP:面向切面编程,通过预编译的方式和运行期间动态代理实现程序功能的统一维护。
    • 其实 AOP 也是 OOP 的延续,在 Spring 框架中是一个非常重要的内容。
    • 使用 AOP 可以对业务逻辑的各个部分进行隔离,从而使各个模块间的业务逻辑耦合度降低,提高代码的可复用性,同时也能提高开发效率。
  • AOP 的核心技术实现主要是:动态代理的使用,就像你可以给一个接口的实现类,使用代理的方式替换掉这个代理类,使用代理类来处理你需要的逻辑。

动态代理

@Test
public void test_proxy_class() {IUserService userService = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IUserService.class}, (proxy, method, args) -> "你被代理了!");String result = userService.queryUserInfo();System.out.println("测试结果:" + result);
}

测试结果


测试结果:你被代理了!
  • 代理类的实现就是使用 Proxy.newProxyInstance 方法。
  • 那么有了一个基本的思路后,解析来就考虑怎么给方法做代理,而不是代理类?另外怎么去代理所有符合某些规则的所有类中方法?
  • 如果可以代理掉所有类的方法,就可以做一个方法拦截器,给所有被代理的方法添加一些自定义处理。如:打印日志、记录耗时、监控异常等。

二、设计:基于JDK、Cglib实现AOP切面

💡 如何给符合规则的方法做代理?怎么做完代理方法的案例后,把类的职责拆分出来?

  • 这两个功能点的实现,都是以切面的思想进行设计和开发。

在这里插入图片描述

  • 就像你在使用 Spring AOP 一样,只处理一些需要被拦截的方法。在拦截方法后,执行你对方法的扩展操作。
  • 需要先实现一个可以代理方法的 Proxy,其实代理方法主要是使用到方法拦截器类处理方法的调用 MethodInterceptor#invoke,而不是直接使用 invoke 方法中的入参 Method method 进行 method.invoke(targetObj, args)
  • 除了以上的核心功能实现,还需要使用到 org.aspectj.weaver.tools.PointcutParser 处理拦截表达式 execution(* com.lino.springframework.test.bean.IUserService.*(..)),有了方法代理和处理拦截,就可以设计出一个 AOP 的雏形了。

三、实现:基于JDK、Cglib实现AOP切面

3.0 引入依赖

<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version>
</dependency>

3.1 工程结构

spring-step-11
|-src|-main|	|-java|		|-com.lino.springframework|			|-aop|			|	|-aspectj|			|	|	|-AspectJExpressionPointcut.java|			|	|-framework|			|	|	|-AopProxy.java|			|	|	|-Cglib2AopProxy.java|			|	|	|-JdkDynamicAopProxy.java|			|	|	|-ReflectiveMethodInvocation.java|			|	|-AdvisedSupport.java|			|	|-ClassFilter.java|			|	|-MethodMatcher.java|			|	|-Pointcut.java|			|	|-TargetSource.java|			|-beans|			|	|-factory|			|	|	|-config|			|	|	|	|-AutowireCapableBeanFactory.java|			|	|	|	|-BeanDefinition.java|			|	|	|	|-BeanFactoryPostProcessor.java|			|	|	|	|-BeanPostProcessor.java|			|	|	|	|-BeanReference.java|			|	|	|	|-ConfigurableBeanFactory.java|			|	|	|	|-SingletonBeanRegistry.java|			|	|	|-support|			|	|	|	|-AbstractAutowireCapableBeanFactory.java|			|	|	|	|-AbstractBeabDefinitionReader.java|			|	|	|	|-AbstractBeabFactory.java|			|	|	|	|-BeabDefinitionReader.java|			|	|	|	|-BeanDefinitionRegistry.java|			|	|	|	|-CglibSubclassingInstantiationStrategy.java|			|	|	|	|-DefaultListableBeanFactory.java|			|	|	|	|-DefaultSingletonBeanRegistry.java|			|	|	|	|-DisposableBeanAdapter.java|			|	|	|	|-FactoryBeanRegistrySupport.java|			|	|	|	|-InstantiationStrategy.java|			|	|	|	|-SimpleInstantiationStrategy.java|			|	|	|-support|			|	|	|	|-XMLBeanDefinitionReader.java|			|	|	|-Aware.java|			|	|	|-BeanClassLoaderAware.java|			|	|	|-BeanFactory.java|			|	|	|-BeanFactoryAware.java|			|	|	|-BeanNameAware.java|			|	|	|-ConfigurableListableBeanFactory.java|			|	|	|-DisposableBean.java|			|	|	|-FactoryBean.java|			|	|	|-HierarcgicalBeanFactory.java|			|	|	|-InitializingBean.java|			|	|	|-ListableBeanFactory.java|			|	|-BeansException.java|			|	|-PropertyValue.java|			|	|-PropertyValues.java|			|-context|			|	|-event|			|	|	|-AbstractApplicationEventMulticaster.java|			|	|	|-ApplicationContextEvent.java|			|	|	|-ApplicationEventMulticaster.java|			|	|	|-ContextclosedEvent.java|			|	|	|-ContextRefreshedEvent.java|			|	|	|-SimpleApplicationEventMulticaster.java|			|	|-support|			|	|	|-AbstractApplicationContext.java|			|	|	|-AbstractRefreshableApplicationContext.java|			|	|	|-AbstractXmlApplicationContext.java|			|	|	|-ApplicationContextAwareProcessor.java|			|	|	|-ClassPathXmlApplicationContext.java|			|	|-ApplicationContext.java|			|	|-ApplicationContextAware.java|			|	|-ApplicationEvent.java|			|	|-ApplicationEventPublisher.java|			|	|-ApplicationListener.java|			|	|-ConfigurableApplicationContext.java|			|-core.io|			|	|-ClassPathResource.java|			|	|-DefaultResourceLoader.java|			|	|-FileSystemResource.java|			|	|-Resource.java|			|	|-ResourceLoader.java|			|	|-UrlResource.java|			|-util|			|	|-ClassUtils.java|-test|-java|-com.lino.springframework.test|-bean|	|-IUserService.java|	|-UserService.java|	|-UserServiceInterceptor.java|-ApiTest.java|-resources|-spring.xml

3.2 AOP切点表达式和使用以及基于JDK和CGLIB的动态代理类图

在这里插入图片描述

  • 整个类图就是 AOP 实现核心逻辑的地方,上面部分是关于方法的匹配实现,下面从 AopProxy 开始是关于方法的代理操作。
  • AspectJExpressionPointcut 的核心功能主要依赖于 aspectj 组件并处理 Pointcut、ClassFilter、MethodMatcher 接口实现,专门用于处理类和方法的匹配过滤操作。
  • AopProxy 是代理的抽象对象,它的实现主要是基于 JDK 的代理和 Cglib 代理。

3.3 切点表达式

3.3.1 类匹配接口

ClassFilter.java

package com.lino.springframework.aop;/*** @description: 类匹配接口*/
public interface ClassFilter {/*** 匹配类** @param clazz 类类型* @return 是否匹配类*/boolean matches(Class<?> clazz);
}
  • 定义类匹配类,用于切点好到给定的接口和目标类

3.3.2 匹配方法接口

MethodMatcher.java

package com.lino.springframework.aop;import java.lang.reflect.Method;/*** @description: 匹配方法接口*/
public interface MethodMatcher {/*** 匹配方法** @param method      匹配方法* @param targetClass 类* @return 是否匹配方法*/boolean matches(Method method, Class<?> targetClass);
}
  • 方法匹配,找到表达式范围内匹配下的目标类和方法。

3.3.3 切点表达式接口

Pointcut.java

package com.lino.springframework.aop;/*** @description: 切点表达式接口*/
public interface Pointcut {/*** 获取切点中类匹配类** @return 类匹配类*/ClassFilter getClassFilter();/*** 获取切点中匹配方法** @return 匹配方法*/MethodMatcher getMethodMatcher();
}
  • 切入点接口,定义用于获取 ClassFilter、MethodMatcher 两个类,这两个接口获取都是切点表达式提供的内容。

3.3.4 实现切点表达式类

AspectJExpressionPointcut.java

package com.lino.springframework.aop.aspectj;import com.lino.springframework.aop.ClassFilter;
import com.lino.springframework.aop.MethodMatcher;
import com.lino.springframework.aop.Pointcut;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;/*** @description: 切点表达式实现类*/
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();static {SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);}private final PointcutExpression pointcutExpression;public AspectJExpressionPointcut(String expression) {PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());pointcutExpression = pointcutParser.parsePointcutExpression(expression);}@Overridepublic boolean matches(Class<?> clazz) {return pointcutExpression.couldMatchJoinPointsInType(clazz);}@Overridepublic boolean matches(Method method, Class<?> targetClass) {return pointcutExpression.matchesMethodExecution(method).alwaysMatches();}@Overridepublic ClassFilter getClassFilter() {return this;}@Overridepublic MethodMatcher getMethodMatcher() {return this;}
}
  • 切点表达式实现了 Pointcut, ClassFilter, MethodMatcher,三个接口定义方法,同时这个类主要是对 aspectj 包提供的表达式校验方法使用。
  • 匹配 matches
    • pointcutExpression.couldMatchJoinPointsInType(clazz)
    • pointcutExpression.matchesMethodExecution(method).alwaysMatches()

3.4 包装切面通知信息

3.4.1 被代理的目标对象

TargetSource.java

package com.lino.springframework.aop;/*** @description: 被代理的目标对象*/
public class TargetSource {private final Object target;public TargetSource(Object target) {this.target = target;}/*** 获取目标对象列表** @return 目标对象列表*/public Class<?>[] getTargetClass() {return this.target.getClass().getInterfaces();}/*** 获取目标对象** @return 目标对象*/public Object getTarget() {return this.target;}
}

3.4.2 包装切面通知消息

AdvisedSupport.java

package com.lino.springframework.aop;import org.aopalliance.intercept.MethodInterceptor;/*** @description: 包装切面通知信息*/
public class AdvisedSupport {/*** 被代理的目标对象*/private TargetSource targetSource;/*** 方法拦截器*/private MethodInterceptor methodInterceptor;/*** 方法匹配器(检查目标方法是否符合通知条件)*/private MethodMatcher methodMatcher;public TargetSource getTargetSource() {return targetSource;}public void setTargetSource(TargetSource targetSource) {this.targetSource = targetSource;}public MethodInterceptor getMethodInterceptor() {return methodInterceptor;}public void setMethodInterceptor(MethodInterceptor methodInterceptor) {this.methodInterceptor = methodInterceptor;}public MethodMatcher getMethodMatcher() {return methodMatcher;}public void setMethodMatcher(MethodMatcher methodMatcher) {this.methodMatcher = methodMatcher;}
}
  • AdvisedSupport:主要用于把代理、拦截、匹配的各项属性包装到一个类中,方便在 Proxy 实现类进行使用。
  • TargetSource:是一个目标对象,在目标对象类中提供 Object 入参属性,以及获取目标类 TargetClass 信息。
  • MethodInterceptor:是一个具体拦截方法实现类,由用户自己实现 MethodInterceptor#invoke 方法,做具体的实现。
  • MethodMatcher:是一个匹配方法,这个对象由 AspectJExpressionPointcut 提供服务。

3.5 代理抽象实现(JDK&Cglib)

3.5.1 反射方法调用

ReflectiveMethodInvocation.java

package com.lino.springframework.aop.framework;import org.aopalliance.intercept.MethodInvocation;import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;/*** @description: 反射方法调用* @author: lingjian* @createDate: 2022/12/2 9:44*/
public class ReflectiveMethodInvocation implements MethodInvocation {/*** 目标对象*/protected final Object target;/*** 方法*/protected final Method method;/*** 入参*/protected final Object[] arguments;public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {this.target = target;this.method = method;this.arguments = arguments;}@Overridepublic Method getMethod() {return method;}@Overridepublic Object[] getArguments() {return arguments;}@Overridepublic Object proceed() throws Throwable {return method.invoke(target, arguments);}@Overridepublic Object getThis() {return target;}@Overridepublic AccessibleObject getStaticPart() {return method;}
}

3.5.2 AOP代理接口

AopProxy.java

package com.lino.springframework.aop.framework;/*** @description: AOP代理接口*/
public interface AopProxy {/*** 获取代理对象** @return 代理对象*/Object getProxy();
}
  • 定义一个标准接口,用于获取代理类。因为具体实现代理的方式可以有 JDK 方式,也可以是 Cglib 方式,所以定义接口会更加方便管理。

3.5.3 JDK 动态代理

JdkDynamicAopProxy.java

package com.lino.springframework.aop.framework;import com.lino.springframework.aop.AdvisedSupport;
import org.aopalliance.intercept.MethodInterceptor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @description: JDK 动态代理*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {private final AdvisedSupport advised;public JdkDynamicAopProxy(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object getProxy() {return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {MethodInterceptor methodInterceptor = advised.getMethodInterceptor();return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));}return method.invoke(advised.getTargetSource().getTarget(), args);}
}
  • 基于 JDK 实现的代理类,需要实现 AopProxyInvocationHandler,这样就可以把代理对象 getProxy 和反射调用方法 invoke 分开处理了。
  • getProxy 方法中的是代理一个对象的操作,需要提供入参 ClassLoaderAdvisedSupport 和当前类 this,因为这个类提供了 invoke 方法。
  • invoke 方法中主要处理匹配的方法后,使得用户自己提供的方法拦截实现,做反射调用 methodInterceptor.invoke
  • 这里还有一个 ReflectiveMethodInvocation,其实它就是一个入参的包装信息,提供了入参对象:目标对象、方法、入参。

3.5.4 Cglib代理

Cglib2AopProxy.java

package com.lino.springframework.aop.framework;import com.lino.springframework.aop.AdvisedSupport;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;/*** @description: Cglib代理*/
public class Cglib2AopProxy implements AopProxy {private final AdvisedSupport advised;public Cglib2AopProxy(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object getProxy() {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());enhancer.setInterfaces(advised.getTargetSource().getTargetClass());enhancer.setCallback(new DynamicAdvisedInterceptor(advised));return enhancer.create();}private static class DynamicAdvisedInterceptor implements MethodInterceptor {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {return advised.getMethodInterceptor().invoke(methodInvocation);}return methodInvocation.proceed();}}private static class CglibMethodInvocation extends ReflectiveMethodInvocation {private final MethodProxy methodProxy;public CglibMethodInvocation(Object target, Method method, Object[] arguments, MethodProxy methodProxy) {super(target, method, arguments);this.methodProxy = methodProxy;}@Overridepublic Object proceed() throws Throwable {return this.methodProxy.invoke(this.target, this.arguments);}}
}
  • 基于 Cglib 使用 Enhancer 代理的类可以在运行期间为接口使用底层 ASM 字节码增强技术处理对象的代理对象生成,因此被代理类不需要实现任何接口。
  • 关于扩展用户拦截方法,主要在 Enhancer#setCallback 中处理,用户自己的新增的拦截处理。
    • 这里可以看到 DynamicAdvisedInterceptor#intercept 匹配方法后做了相应的反射操作。

四、测试:基于JDK、Cglib实现AOP切面

4.1 添加测试配置

4.1.1 用户接口

IUserService.java

package com.lino.springframework.test.bean;/*** @description: 用户接口*/
public interface IUserService {/*** 查询用户信息** @return 用户信息*/String queryUserInfo();/*** 注册用户** @param userName 用户名* @return 用户信息*/String register(String userName);
}

4.1.2 用户接口实现类

UserService.java

package com.lino.springframework.test.bean;import java.util.Random;/*** @description: 用户接口实现类*/
public class UserService implements IUserService {@Overridepublic String queryUserInfo() {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return "张三,100001,杭州";}@Overridepublic String register(String userName) {try {Thread.sleep(new Random(1).nextInt(100));} catch (InterruptedException e) {e.printStackTrace();}return "注册用户:" + userName + " success!";}
}
  • UserService 中提供了2个不同方法。查询和注册。

4.1.3 自定义用户拦截方法

UserServiceInterceptor.java

package com.lino.springframework.test.bean;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;/*** @description: 用户拦截器*/
public class UserServiceInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {long start = System.currentTimeMillis();try {return invocation.proceed();} finally {System.out.println("监控 - Begin By AOP");System.out.println("方法名称:" + invocation.getMethod());System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");System.out.println("监控 - End\r\n");}}
}
  • 用户自定义的拦截方法需要实现 MethodInterceptor 接口的 invoke 方法,使用方式于 Spring AOP 类似,也是包装 invocation.proceed() 放行,并在 finally 中添加监控信息。

4.2 单元测试

4.2.1 代理方法测试

ApiTest.java

@Test
public void test_proxy_method() {// 目标对象Object targetObj = new UserService();// AOP代理IUserService proxy = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), targetObj.getClass().getInterfaces(), new InvocationHandler() {// 方法匹配器MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* com.lino.springframework.test.bean.IUserService.*(..))");@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (methodMatcher.matches(method, targetObj.getClass())) {// 方法拦截器MethodInterceptor methodInterceptor = invocation -> {long start = System.currentTimeMillis();try {return invocation.proceed();} finally {System.out.println("监控 - Begin By AOP");System.out.println("方法名称:" + invocation.getMethod());System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");System.out.println("监控 - End\r\n");}};return methodInterceptor.invoke(new ReflectiveMethodInvocation(targetObj, method, args));}return method.invoke(targetObj, args);}});String result = proxy.queryUserInfo();System.out.println("测试结果:" + result);
}
  • 整个案例的目标是把一个 UserService 当成目标对象,对类中的所有方法进行拦截添加监控信息打印处理。
  • 从案例中可以看到有代理的实现 Proxy.newProxyInstance,有方法的匹配 MethodMatcher,有反射的调用 invoke(Object proxy, Method method, Object[] args),也有用户自己拦截方法后的操作。
  • 这样看其实就和我们使用的 AOP 非常类似。

测试结果

监控 - Begin By AOP
方法名称:public abstract java.lang.String com.lino.springframework.test.bean.IUserService.queryUserInfo()
方法耗时:86ms
监控 - End测试结果:张三,100001,杭州
  • 从测试结果看,我们已经对 UserService#queryUserInfo 方法进行了拦截监控操作。

拆解案例

在这里插入图片描述

  • 拆解过程参考上图,把代理对象拆解出来,因为它可以是 JDK 的实现也可以是 Cglib 的处理。
  • 方法匹配器操作其实已经是一个单独的实现类了,不过我们还需要把传入的目标对象、方法匹配、拦截方法,都进行统一的包装,方便外部调用时进行一个入参透传。
  • 最后其实就是 ReflectiveMethodInvocation 的使用,它目前已经是实现 MethodInvocation 接口的一个包装后的类。
    • 参数信息包括:调用的对象、调用的方法、调用的入参。

4.2.2 匹配方法测试

ApiTest.java

@Test
public void test_aop() throws NoSuchMethodException {AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* com.lino.springframework.test.bean.UserService.*(..))");Class<UserService> clazz = UserService.class;Method method = clazz.getDeclaredMethod("queryUserInfo");System.out.println(pointcut.matches(clazz));System.out.println(pointcut.matches(method, clazz));
}

测试结果

true
true
  • 这是一个匹配方法的测试,可以看看拦截的方法与对应的对象是否匹配。

4.2.3 单元测试

ApiTest.java

@Test
public void test_dynamic() {// 目标对象IUserService userService = new UserService();// 组装代理信息AdvisedSupport advisedSupport = new AdvisedSupport();advisedSupport.setTargetSource(new TargetSource(userService));advisedSupport.setMethodInterceptor(new UserServiceInterceptor());advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* com.lino.springframework.test.bean.IUserService.*(..))"));// 代理对象(JDKDynamicAopProxy)IUserService proxy_jdk = (IUserService) new JdkDynamicAopProxy(advisedSupport).getProxy();// 测试调用System.out.println("测试结果:" + proxy_jdk.queryUserInfo());// 代理对象(Cglib2AopProxy)IUserService proxy_cglib = (IUserService) new Cglib2AopProxy(advisedSupport).getProxy();// 测试调用System.out.println("测试结果:" + proxy_cglib.register("小零"));
}
  • 整个案例测试了 AOP 在与 Spring 结合前的核心代码,包括什么是目标对象、怎么组装代理信息、如何调用代理对象等。
  • AdvisedSupport:包装了目标对象、用户自己实现的拦截方法以及方法匹配表达式。
  • 之后就是分别调用 JdkDynamicAopProxyCglib2AopProxy,两个不同方式实现的代理类,看看是否可以成功拦截方法。

测试结果

监控 - Begin By AOP
方法名称:public abstract java.lang.String com.lino.springframework.test.bean.IUserService.queryUserInfo()
方法耗时:90ms
监控 - End测试结果:张三,100001,杭州监控 - Begin By AOP
方法名称:public java.lang.String com.lino.springframework.test.bean.UserService.register(java.lang.String)
方法耗时:99ms
监控 - End测试结果:注册用户:小零 success!
  • AOP 功能定义一样,我们可以通过这样的代理方式、方法匹配和拦截后,在对应的目标方法下,做了拦截操作进行监控信息打印。

五、总结:基于JDK、Cglib实现AOP切面

  • 本文对 Proxy#newProxyInstanceMethodInterceptor#invoke 的使用验证切面核心原理以及再把功能拆解到 Spring 框架实现中。
    • 可以看到一个貌似复杂的技术其实核心内容往往没有太多,但因为需要为了满足后续更多的扩展就需要进行职责解耦和包装,通过这样设计模式的使用,以此让调用方能更加简化,自身也可以不断按需扩展。
  • AOP 的功能实现目前还没有与 Spring 结合,只是对切面技术的一个具体实现,可以先学到:如何处理代理对象、过滤方法、拦截方法,以及使用 JDKCglib 代理的区别。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/103279.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构初阶】二、 线性表里的顺序表

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【数据结构初阶】一. 复杂度讲解_高高的胖子的博客-CSDN博客 1 . 线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实…

[Linux]动静态库

[Linux]动静态库 文章目录 [Linux]动静态库见一见库存在库的原因编写库模拟编写静态库模拟使用静态库模拟编写动态库模拟使用静态库 库的加载原理静态库的加载原理动态库的加载原理 库在可执行程序中的编址策略静态库在可执行程序中的编址策略动态库在可执行程序中的编址策略 见…

TinTin Web3 动态精选:以太坊基金会推出 EELS、Arbitrum Stylus 上线

TinTin 快讯由 TinTinLand 开发者技术社区打造&#xff0c;旨在为开发者提供最新的 Web3 新闻、市场时讯和技术更新。TinTin 快讯将以周为单位&#xff0c; 汇集当周内的行业热点并以快讯的形式排列成文。掌握一手的技术资讯和市场动态&#xff0c;将有助于 TinTinLand 社区的开…

YOLO目标检测——红火蚂蚁识别数据集+已标注yolo格式标签下载分享

实际项目应用&#xff1a;目标检测红火蚂蚁识别数据集在农业、生态学、环境保护、城市管理和学术研究等领域都有着广泛的应用。通过准确识别和定位红火蚂蚁&#xff0c;可以帮助我们更好地了解和管理这一入侵物种&#xff0c;从而减少其对环境和经济的负面影响。数据集说明&…

基于Docker从零到一实操MySql的主从复制

文章目录 一、在Docker上安装&#xff0c;启动MySQL查看docker是否安装成功安装mysql查看mysql镜像进入mysql后台操作docker Volume&#xff08;卷&#xff09;入门 MySql的主从复制1. 创建MySQL主从复制的网络2. 创建MySQL主服务器3. 创建MySQL从服务器4. 配置主从同步5.测试主…

Activiti7工作流引擎:在线流程编辑器Activiti Modoler5.x

一&#xff1a;简介 有的时候我们的流程图需要业务人员自己绘制&#xff0c;然后使用自己绘制的流程图&#xff0c;此时就需要一个在线流程图编辑器需要集成到我们的web系统中。Activiti Modoler是Activiti官方推出的在线流程编辑器。 二&#xff1a;pom.xml <dependency…

Python - 队列【queue】task_done()和join()基本使用

一. 前言 task_done()是Python中queue模块提供的方法&#xff0c;用于通知队列管理器&#xff0c;已经处理完了队列中的一个项目。 queue.task_done()是Queue对象的一个方法&#xff0c;它用于通知Queue对象&#xff0c;队列中的某一项已经被处理完毕。通常在使用Queue对象时…

电脑磁盘分区形式是什么?如何更改?

磁盘分区形式介绍 在了解为什么以及如何更改分区形式之前&#xff0c;让我们对磁盘分区形式有一个基本的了解。一般来说&#xff0c;分区形式是指主引导记录&#xff08;MBR&#xff09;和 GUID 分区表&#xff08;GPT&#xff09;。 MBR和GPT是Windows系统中常用…

洛谷 LGR SCP-J 2023 c++语言模拟试题 10. 以下程序片段的时间复杂度为( )

之前在牛客的一个群中看到有位哥们发的题 好像是洛谷哪次的模拟题&#xff0c;还写着什么 LGR SCP-J 2023 c语言模拟试题 题目 就是给段代码询问时间复杂度 for (int i1; i<n; i){for (int j1; j<n; ji){for (int k1; k<n; k j){}} } 跑代码 一开始想不出怎么解就…

【CMake工具】工具CMake编译轻度使用(C/C++)

目录 CMake编译工具 一、CMake概述 二、CMake的使用 2.1 注释 2.1.1 注释行 2.1.2 注释块 2.2 源文件 2.1.1 共处一室 2.1.2 VIP包房 2.3 私人定制 2.2.1 定义变量 2.2.2 指定使用的C标准 2.2.3 指定输出的路径 2.4 搜索文件 2.3.1 方式1 2.3.2 方式2 2.5 包含…

岩土工程安全监测利器:振弦采集仪的发展

岩土工程安全监测利器&#xff1a;振弦采集仪的发展 岩土工程安全监测是保障建筑物、地下工程和地质环境安全稳定运行的重要手段。传统上&#xff0c;监测手段主要依靠人工巡视以及基础设施安装的传感器&#xff0c;但是这些方法都存在着缺陷。人工巡视存在的问题是数据采集精…

云原生Kubernetes:pod基础

目录 一、理论 1.pod 2.pod容器分类 3.镜像拉取策略&#xff08;image PullPolicy&#xff09; 二、实验 1.Pod容器的分类 2.镜像拉取策略 三、问题 1.apiVersion 报错 2.pod v1版本资源未注册 3.取行显示指定pod信息 四、总结 一、理论 1.pod (1) 概念 Pod是ku…