赞
踩
JDK动态代理是Java语言提供的一种实现动态代理的方式,其基本原理是利用反射机制在运行时动态生成代理类和代理对象。
基本原理:
InvocationHandler
接口的类,该类负责实际的代理逻辑。InvocationHandler
接口只有一个方法invoke(Object proxy, Method method, Object[] args)
,当代理对象的方法被调用时,invoke
方法会被调用,并在其中执行代理逻辑。Proxy
类的newProxyInstance
方法动态地创建代理对象。newProxyInstance
方法接受三个参数:ClassLoader、一个接口数组和一个InvocationHandler
对象。在运行时,Proxy
类会动态生成一个实现了指定接口的代理类,并通过传入的InvocationHandler
对象来调用实际的代理逻辑。InvocationHandler
接口的invoke
方法,该方法会根据被调用的方法和传入的参数执行相应的代理逻辑。使用场景:
Spring AOP的实现基于代理模式和装饰器模式,在目标方法执行前后或异常抛出时,通过代理对象来执行额外的逻辑,如日志记录、事务管理、权限控制等。通过配置切面和通知,可以将这些额外逻辑统一地应用到多个目标类的方法中,从而实现横切关注点的分离和复用。
在Spring AOP中,主要利用了JDK动态代理和CGLIB动态代理两种方式。
java.lang.reflect.Proxy
类来创建代理对象,该类要求被代理的类必须实现至少一个接口。InvocationHandler
接口的实现类来执行增强逻辑。本文主要结合动态代理的维度以及织入切面逻辑来分析源码,其它相关源码,读者感兴趣可自行去分析。
织入切面逻辑的过程:
JdkDynamicAopProxy
类的实现做一些准备工作,包括声明变量、初始化变量、定义静态成员等。
在 getProxy
方法中,会创建 Proxy.newProxyInstance
,并传入 JdkDynamicAopProxy
的实例作为 InvocationHandler
。
用于确定最终使用的类加载器,确保动态代理类能够正确加载所需的类。
主要用于创建代理实例,其中包含了一些安全性检查和异常处理。
InvocationHandler
接口定义了一个用于处理代理对象方法调用的统一入口,当代理对象的方法被调用时,会触发invoke
方法的执行,通过实现invoke
方法来定义代理对象方法调用时的行为,例如添加日志、实现权限控制等。
在
invoke
方法中,会根据方法名和参数,调用对应的拦截器。invoke()的实现类较多,本文解读AopProxyChain实现类下的invoke方法。
主要用于代理对象的调用处理程序的实现,用于处理代理对象的方法调用。
承接invoke方法实现,主要是根据拦截器链的情况来决定是直接调用目标方法还是通过拦截器链来调用,并在方法调用结束后进行相应的处理。
在 invoke
方法中,JdkDynamicAopProxy
会调用 AopProxyChain
对象的 proceed
方法。
AopProxyChain
封装了拦截器链,负责按照顺序执行拦截器的逻辑。
通过对 Spring 源码的解析,学习如何编写自定义的 AOP 拦截器
编写自定义的 AOP 拦截器步骤:
使用注解形式配置的Demo:
CustomInterceptor
,实现 MethodInterceptor
接口。public class CustomInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 在目标方法执行前输出日志
System.out.println("Before invoking method: " + invocation.getMethod().getName());
// 执行目标方法
Object result = invocation.proceed();
// 在目标方法执行后输出日志
System.out.println("After invoking method: " + invocation.getMethod().getName());
return result;
}
}
CustomAnnotation
,用来标记需要被拦截的方法。@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}
UserService
和 UserServiceImpl
,在需要拦截的方法上添加 CustomAnnotation
注解。public interface UserService {
@CustomAnnotation
void addUser(String username);
}
public class UserServiceImpl implements UserService {
@Override
@CustomAnnotation
public void addUser(String username) {
System.out.println("User added: " + username);
}
}
@Configuration
public class AppConfig {
/**
* 返回一个 UserService 实例
*/
@Bean
public UserService userService() {
return new UserServiceImpl();
}
/**
* 返回一个 CustomInterceptor 的实例,即自定义的拦截器
*/
@Bean
public CustomInterceptor customInterceptor() {
return new CustomInterceptor();
}
/**
* 返回一个 DefaultAdvisorAutoProxyCreator 实例,负责自动代理被 @AspectJ 注解标记的 Bean
*/
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
/**
* 返回一个 DefaultPointcutAdvisor 实例,将拦截器和切点绑定在一起
*/
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
// 将自定义的拦截器设置为 Advisor 的 advice,即在目标方法执行前后所执行的逻辑
advisor.setAdvice(customInterceptor());
// 设置切点,即确定在哪些方法上应用拦截器的条件
advisor.setPointcut(annotationMatchingPointcut());
return advisor;
}
/**
* 返回一个 AnnotationMatchingPointcut 实例,切点用于匹配带有 CustomAnnotation 注解的方法
*/
@Bean
public AnnotationMatchingPointcut annotationMatchingPointcut() {
return AnnotationMatchingPointcut.forMethodAnnotation(CustomAnnotation.class);
}
}
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
// 在执行 addUser 方法之前,拦截器执行了自定义的前置逻辑,并在方法执行完毕后执行了自定义的后置逻辑
userService.addUser("Alice");
}
}
// 输出结果
Before invoking method: addUser
User added: Alice
After invoking method: addUser
前程万里,全要各人自去努力
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。