框架都是基于JDK的,看源码一直追溯到JDK才算是合格
一、前置知识
- 代理模式(Proxy Pattern):是23种设计模式中的一种
- 编程思想:不能随便修改源码,如果需要修改源码,通过代理的方式来拓展
1.1 静态代理
静态代理是基于接口,需要自己手写代理类
代理对象,引用真实对象
缺点:每次修改接口,需要改动代理对象,不灵活
@Slf4j
public class StaticProxyStudent implements IStudent {
private IStudent target;
public StaticProxyStudent(IStudent target) {
this.target = target;
}
@Override
public void insert() {
log.info("前置增强逻辑");
target.insert();
log.info("后置增强逻辑");
}
}
1.2 JDK动态代理
自己写一个方法拦截器Handler,实现增强逻辑
@Slf4j
public class TransactionHandler implements InvocationHandler {
private Object target;
public TransactionHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
//判断方法是否要增强的逻辑
if ("insert".equals(method.getName())) {
log.info("前置增强逻辑");
result = method.invoke(target, args);
log.info("后置增强逻辑");
} else {
result = method.invoke(target, args);
}
return result;
}
}
使用Proxy,生成代理对象
@Test
public void JDKProxyTest() {
//真实对象
IStudentService target = new StudentServiceImpl();
//方法拦截处理器
TransactionHandler handler = new TransactionHandler(target);
//代理对象
IStudentService jdkProxy = (IStudentService) Proxy.newProxyInstance(
ProxyTest.class.getClassLoader(),
new Class[]{IStudentService.class},
handler);
jdkProxy.insert();
}
1.3 CGLIB动态代理
如果类没有实现接口,就只能用CGLIB动态代理
@Test
public void CglibProxyTest() {
TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(StudentServiceImpl.class);
enhancer.setCallback(transactionInterceptor);
IStudentService cglibProxy = (IStudentService) enhancer.create();
cglibProxy.insert();
}
方法拦截器
@Slf4j
public class TransactionInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
log.info("前置增强");
//o是代理对象,o的super就是真实对象
//spring中的cglib,会用target指向真实对象,代理对象的属性都为null
Object result = methodProxy.invokeSuper(o, objects);
log.info("后置增强");
return result;
}
}
1.4 Spring中的代理
- Spring中,无论JDK还是CGLIB,统一使用target指向真实对象。因为依赖注入过于复杂,统一在真实对象中处理,代理对象中的属性为null
- 类和方法都不能加final
二、入门案例
与最简单的JDK代理相比,做了两个扩展
- 方法匹配器,扩展点一,底层使用了AspectJ
- 反射调用,扩展点二,使用了AopAlliance做统一包装
@Test
public void test_proxy_jdk_alliance() {
// 目标对象(可以替换成任何的目标对象)
Object targetObj = new UserService();
// AOP 代理
IUserService proxy = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), targetObj.getClass().getInterfaces(), new InvocationHandler() {
// 方法匹配器,扩展点一,底层使用了AspectJ
MethodMatcher methodMatcher = new AspectJExpressionPointcut("execution(* cn.shopifymall.springframework.test.bean.IUserService.*(..))");
@Override
public 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 {
// AOP逻辑,计算方法执行时间
System.out.println("监控 - Begin By AOP");
System.out.println("方法名称:" + invocation.getMethod().getName());
System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("监控 - End\r\n");
}
};
// 反射调用,扩展点二,使用了AopAlliance做统一包装
return methodInterceptor.invoke(new ReflectiveMethodInvocation(targetObj, method, args));
}
// 方法未匹配切点,直接调用
return method.invoke(targetObj, args);
}
});
String result = proxy.queryUserInfo();
System.out.println("测试结果:" + result);
}
执行结果,打印出了方法的执行耗时
模拟调用dao,查询user信息
监控 - Begin By AOP
方法名称:queryUserInfo
方法耗时:1ms
监控 - End
测试结果:查询完毕
三、定义要素
3.1 AspectJ包装
类匹配接口
- 通知是否应适用于给定的目标类别
public interface ClassFilter {
/**
* Should the pointcut apply to the given interface or target class?
* @param clazz the candidate target class
* @return whether the advice should apply to the given target class
*/
boolean matches(Class<?> clazz);
}
方法匹配接口
- 通知是否应适用于给定的方法
public interface MethodMatcher {
/**
* Perform static checking whether the given method matches. If this
* @return whether this method matches statically
*/
boolean matches(Method method, Class<?> targetClass);
}
切点接口
- 返回类匹配器和方法匹配器
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never <code>null</code>)
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never <code>null</code>)
*/
MethodMatcher getMethodMatcher();
}
切点表达式最终实现
- 借助AspectJ实现,完成了扩展点一
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
/**
* 底层用来描述切入点原语
*/
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
static {
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
/**
* 保存解析后的切点表达式
*/
private final PointcutExpression pointcutExpression;
/**
* 构造方法,解析传入的切点表达式
* @param expression
*/
public AspectJExpressionPointcut(String expression) {
PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
pointcutExpression = pointcutParser.parsePointcutExpression(expression);
}
/**
* 类型匹配
* @param clazz the candidate target class
* @return
*/
@Override
public boolean matches(Class<?> clazz) {
return pointcutExpression.couldMatchJoinPointsInType(clazz);
}
/**
* 方法匹配
* @param method
* @param targetClass
* @return
*/
@Override
public boolean matches(Method method, Class<?> targetClass) {
return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
}
3.2 Aop_Alliance包装
打包AOP相关的所有信息
- 目标对象,被代理的真实对象
- 方法拦截器,使用aop_alliance提供的接口做统一包装,需要用户自己实现(扩展二)
- 方法匹配器,使用了AspectJ最终实现
@Data
public class AdvisedSupport {
// 目标对象
private TargetSource targetSource;
// 增强逻辑
private MethodInterceptor methodInterceptor;
// 方法匹配器
private MethodMatcher methodMatcher;
}
目标对象类
public class TargetSource {
private final Object target;
public TargetSource(Object target) {
this.target = target;
}
public Class<?>[] getTargetClass(){
return this.target.getClass().getInterfaces();
}
public Object getTarget(){
return this.target;
}
}
反射方法调用类
- 实现MethodInvocation接口,由aop_alliance提供的接口做统一包装
- 最终会调用proceed,调用真实对象的方法
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;
}
@Override
public Method getMethod() {
return method;
}
@Override
public Object[] getArguments() {
return arguments;
}
@Override
public Object proceed() throws Throwable {
return method.invoke(target, arguments);
}
@Override
public Object getThis() {
return target;
}
@Override
public AccessibleObject getStaticPart() {
return method;
}
}
3.3 代理实现
代理接口
- 定义一个标准接口,用于获取代理类。因为具体实现代理的方式可以有 JDK 方式,也可以是 Cglib 方式
/**
* Aop接口,JDK CGLIB两种实现
*
* @Author 孤风雪影
* @Email gitee.com/efairy520
* @Date 2025/1/5 7:20
* @Version 1.0
*/
public interface AopProxy {
Object getProxy();
}
JDK实现类
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
/**
* 切面
*/
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//看看切点是否匹配
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
//MethodInterceptor和MethodInvocation是AopAlliance包下的
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
//不匹配,直接用原始对象执行方法
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
CGLIB实现类
public class Cglib2AopProxy implements AopProxy {
private final AdvisedSupport advised;
public Cglib2AopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public 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;
}
@Override
public 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())) {
//AopAlliance的包装类
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;
}
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.target, this.arguments);
}
}
}
JDK与CGLIB的相似点
- 调用代理方法,都是使用aop_alliance提供的
MethodInterceptor.invoke(MethodInvocation invocation)
调用
四、测试
新建Eat接口
public interface Eat {
String eatFish(String fishName);
}
改造Cat类,实现Eat接口
@Slf4j
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Cat implements Eat{
private String name;
private int weight;
@Override
public String eatFish(String fishName) {
log.info("猫正在吃鱼");
return "吃了一条" + fishName;
}
}
新建方法拦截器,提供代理逻辑
public class CatInterceptor implements MethodInterceptor {
@Override
public 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");
}
}
}
测试结果
- 可以看到方法耗时
02:10:31.331 [main] INFO cn.shopifymall.springframework.test.bean.Cat - 猫正在吃鱼
监控 - Begin By AOP
方法名称:public abstract java.lang.String cn.shopifymall.springframework.test.bean.Eat.eatFish(java.lang.String)
方法耗时:4ms
监控 - End
02:10:31.334 [main] INFO cn.shopifymall.springframework.test.ApiTest - 测试结果:吃了一条大马哈鱼
02:10:31.391 [main] INFO cn.shopifymall.springframework.test.bean.Cat - 猫正在吃鱼
监控 - Begin By AOP
方法名称:public java.lang.String cn.shopifymall.springframework.test.bean.Cat.eatFish(java.lang.String)
方法耗时:9ms
监控 - End
02:10:31.392 [main] INFO cn.shopifymall.springframework.test.ApiTest - 测试结果:吃了一条三文鱼