文章目录
1. 为什么使用ProxyFactory
使用Spring的ProxyFactory
对比Jdk的Proxy
创建静态代理有什么好处?
- Jdk的
Proxy
只支持接口级别的代理;假设类没有实现任何接口时,则需要引入Cglib
的库,使用Cglib
创建代理 - 而Spring的
ProxyFactory
整合了Jdk的Proxy
和Cglib
,使得我们可以使用统一的api来创建代理对象
2. 前置知识-Advice
Advice
- 对被代理对象的增强
常见的三大实现
BeforeAdvice
: 在被代理对象方法执行前执行AfterAdvice
: 在被代理对象方法执行后执行MethodInterceptor
: 在被代理对象方法执行前后执行 ( 最常用 )
接下来我们使用ProxyFactory
创建代理时,就会使用MethodInterceptor
注:Spring创建代理时,最常用的
Aspect
也是MethodInterceptor
例如在使用注解@Aspect
创建代理时:给增强类标注@Aspect
注解,最终该增强类就会被封装成MethodInterceptor
MethodInterceptor
签名
3. 前置知识-Advisor
Advisor
=Advice
+切入点
Advice
具体的增强逻辑切入点
匹配需要被增强的类或方法
常见的两大实现
IntroductionAdvisor
: 可以基于类判断是否进行切入PointcutAdvisor
: 可以基于类和方法判断是否进行切入 ( 最常用 )
注:Spring创建代理时,最常用的
Advisor
就是PointcutAdvisor
例如在使用注解@Pointcut
创建代理时:给类标注@Pointcut
注解,在注解内指定表达式,最终该类就会被封装成PointcutAdvisor
4. 使用ProxyFactory创建静态代理
被代理类定义如下
public class Person {
private final String name;
private Person(String name) {
this.name = name;
}
public void sayHello(String otherName) {
System.out.printf("hello : %s , i'm : %s %n", otherName, this.name);
}
public String personName() {
return "name = " + this.name;
}
}
4.1 基于Advice创建代理
@Test
public void create_proxy_advice() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
// 1. 设置被代理的对象
proxyFactory.setTarget(new Person("zzzj"));
// 2. 添加增强 ( Advice ) 逻辑
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Before
System.out.printf("Before execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));
// 执行方法
Object result = invocation.proceed();
// After
System.out.printf("After execute : %s , result = %s %n", invocation.getMethod().getName(), result);
return result;
}
});
// 3. 创建代理对象
Person proxied = (Person) proxyFactory.getProxy();
proxied.sayHello("Xiao Hong");
}
输出结果
Before execute : sayHello , args = [Xiao Hong]
hello : Xiao Hong , i'm : zzzj
After execute : sayHello , result = null
4.2 基于Advisor创建代理
@Test
public void create_proxy_advisor() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
// 1. 设置被代理的对象
proxyFactory.setTarget(new Person("zzzj"));
// 2. 创建增强 ( Advice )
Advice advice = new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Before
System.out.printf("Before execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));
// 执行方法
Object result = invocation.proceed();
// After
System.out.printf("After execute : %s , result = %s %n", invocation.getMethod().getName(), result);
return result;
}
};
// 3. 创建 ( Advisor )
// 3.1 赋值 { advice } 给 { StaticMethodMatcherPointcutAdvisor }
// 3.2 { StaticMethodMatcherPointcutAdvisor } 是 { PointcutAdvisor }的实现类
Advisor advisor = new StaticMethodMatcherPointcutAdvisor(advice) {
@Override
public boolean matches(Method method, Class<?> targetClass) {
// 仅匹配personName方法
return method.getName().equalsIgnoreCase("personName");
}
};
// 3.3 添加Advisor
proxyFactory.addAdvisor(advisor);
// 4. 创建代理对象
Person proxied = (Person) proxyFactory.getProxy();
// 4.1 调用sayHello()
proxied.sayHello("Xiao Ming");
// 4.2 调用personName()
proxied.personName();
}
hello : Xiao Ming , i'm : zzzj
Before execute : personName , args = []
After execute : personName , result = name = zzzj
根据输出结果可以发现,sayHello()
方法并没有被增强,personName()
方法得到了增强
4.3 ProxyFactory的常用属性:exposeProxy
在代理对象执行方法时,通过this.xxxMethod()
调用其他方法时,xxxMethod()
并不会被增强
原因是this
指向的未被代理的对象
如果希望在当前方法中拿到被增强后的对象,可以借助Spring
的AopContext#currentProxy
只有给ProxyFactory
的exposeProxy
属性设置为true
时 ( 默认为false
):AopContext#currentProxy
才能被使用
public class AopContextTests {
@Test
public void expose_tests() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory(new AopContextTests());
// 1. 设置ExposeProxy为true
proxyFactory.setExposeProxy(true);
// 2. 设置 { Advice } : Advice什么也没有做, 直接执行了方法
proxyFactory.addAdvice((MethodInterceptor) MethodInvocation::proceed);
// 3. 创建代理
AopContextTests proxy = (AopContextTests) proxyFactory.getProxy();
// 4. 调用printThis
proxy.printThis();
// 5. 调用printCurrentProxy()
proxy.printCurrentProxy();
}
void printThis() {
System.out.println("this = " + this.getClass().getName());
}
void printCurrentProxy() {
System.out.println("currentProxy = " + AopContext.currentProxy().getClass().getName());
}
}
输出结果
this = com.zzzj.spring.aop.AopContextTests
currentProxy = com.zzzj.spring.aop.AopContextTests$$EnhancerBySpringCGLIB$$6003f0a6
4.4 强制转换为Advised
通过
ProxyFactory
创建出来的代理对象,Spring都会为其实现Advised
接口
将被代理对象转换为Advised
对象后,可以动态得增加、删除、替换Advisor
@Test
public void cast_to_advised() throws Exception {
ProxyFactory proxyFactory = new ProxyFactory();
// 1. 设置被代理的对象
proxyFactory.setTarget(new Person("zzzj"));
// 2. 添加增强 ( Advice ) 逻辑
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// Before
System.out.printf("Before111 execute : %s , args = %s %n", invocation.getMethod().getName(), Arrays.toString(invocation.getArguments()));
// 执行方法
Object result = invocation.proceed();
// After
System.out.printf("After111 execute : %s , result = %s %n", invocation.getMethod().getName(), result);
return result;
}
});
// 3. 创建代理对象
Person proxied = (Person) proxyFactory.getProxy();
proxied.sayHello("Xiao Hong");
System.out.println("==================================================");
// 4. 强制转换为 { Advised } 类型
Advised advised = (Advised) proxied;
// 删除第一个Advisor
advised.removeAdvisor(0);
// 添加
// advised.addAdvice();
// 移除
// advised.removeAdvice()
// 替换
// advised.replaceAdvisor()
proxied.sayHello("Xiao Ming");
}
输出结果
Before111 execute : sayHello , args = [Xiao Hong]
hello : Xiao Hong , i'm : zzzj
After111 execute : sayHello , result = null
==================================================
hello : Xiao Ming , i'm : zzzj