Spring自定义BeanPostProcessor实现bean的代理Java动态代理知识
上文:https://blog.csdn.net/qq_26437925/article/details/145241149 中大致了解了spring aop的代理的实现,其实就是有个BeanPostProcessor代理了bean对象。顺便复习下java代理相关知识
目录
- 自定义BeanPostProcessor实现aop
- Java动态代理知识
- 动态代理的几种实现方式
- Java基于接口的动态代理
- 例子代码和输出
- 为什么一定要有接口
自定义BeanPostProcessor实现aop
bean A:
@Service
public class A {
public A() {
System.out.println("A()");
}
public void say(){
System.out.println("say A");
}
}
- beanPostProcessor
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
@Service
public class ABeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("a")) {
System.out.println("a BeanPostProcessor postProcessAfterInitialization");
return getProxy(bean);
}
return bean;
}
public Object getProxy(Object targetObject) {
Enhancer enhancer = new Enhancer();
Class<?> superClass = targetObject.getClass();
enhancer.setSuperclass(superClass);
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib before...");
Object res = methodProxy.invokeSuper(o, objects);
return res;
}
};
enhancer.setCallback(interceptor);
Object targetProxy = enhancer.create();
return targetProxy;
}
}
基于cglib代理
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
- config类不用EnableAspectJAutoProxy了
@Configuration
@ComponentScan("com.aop.dependency")
public class ConfigOne {
}
- 测试类
@Test
public void test() throws Exception {
ApplicationContext ctx =
new AnnotationConfigApplicationContext(ConfigOne.class);
A a = (A) ctx.getBean("a");
a.say();
((AnnotationConfigApplicationContext) ctx).close();
}
测试输出
方法执行的代理输出正常
因为Cglib是用父类继承,新增了一个完整的class字节码。所以可以看到A()
构造函数执行了两次, 一次是spring bean生命周期的实例化,一次则是Cglib创建出代理对象执行的。
Java动态代理知识
动态代理的几种实现方式
java对象的产生流程如下:
编译 ClassLoader加载 实例化
| | |
| | |
| | |
.java ------> .class(字节码) ---------------> Class Obj ---------> Class Instance
正因为这个流程,所以在你编写Java代码到运行时具体的Java对象,这个过程可以进行很多操作去改变
常见的动态代理技术如下:
- Java Proxy(接口&反射机制,新增一个完整的class字节码:继承Proxy,实现接口类)
- CGLib(父类继承,新增一个完整的class字节码)
- AspectJ(修改现有字节码)
- JavaAgent(修改现有字节码)
- Byte Buddy,提供api可以在Java应用程序运行时创建和修改Java类,使用例子:https://doctording.blog.csdn.net/article/details/114787289
Java基于接口的动态代理
例子代码和输出
- 接口
public interface Go {
void out();
}
- 其中一个实现类
public class CarGo implements Go{
@Override
public void out() {
System.out.println("car go");
}
}
- 代理handler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
class GoProxyHandler implements InvocationHandler {
private Go go;
private Go goProxy;
public GoProxyHandler(Go go) {
this.go = go;
// newProxyInstance方法的三个参数:
// 1. 用哪个类加载器去加载代理对象
// 2. 动态代理类需要实现的接口
// 3. 动态代理方法在执行时,会调用this里面的invoke方法去执行
this.goProxy = (Go)Proxy.newProxyInstance(
Go.class.getClassLoader(),
new Class<?>[] { Go.class },
this);
}
// 实现方法的增强, 对PayService内部的所有方法都能应用该代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("before go " + methodName);
// 这里注意是go,即实际的实现类
Object rs = method.invoke(go, args);
System.out.println("after go " + methodName);
return rs;
}
// 返回原接口的代理对象,通过反射方式new出来的:Proxy.newProxyInstance
public Go getProxy() {
return goProxy;
}
}
- 测试代码
public class ProxyTest {
public static void main(String[] args) {
Go go = new CarGo();
GoProxyHandler goProxyHandler = new GoProxyHandler(go);
Go goProxy = goProxyHandler.getProxy();
goProxy.out();
Class<?> clazz = goProxy.getClass();
// 输出类的直接超类
Class<?> superclass = clazz.getSuperclass();
System.out.println("直接超类: " + superclass.getName());
// 输出类实现的接口
Class<?> interfaces[] = clazz.getInterfaces();
System.out.print("实现的接口: ");
if (interfaces.length > 0) {
System.out.println(Arrays.stream(interfaces)
.map(Class::getName)
.collect(Collectors.joining(", ")));
} else {
System.out.println("无");
}
}
}
为什么一定要有接口
直观的来看,可以看到最后的代理类是继承了 java.lang.reflect.Proxy
,实现了自己的接口
而java是单继承,可实现多接口的模式。
假如没有接口,而又要改变这个类,则必然要继承这个类,而java动态代理的实现必须要继承java.lang.reflect.Proxy
,这就变成多继承了,不允许。
另外接口本身就是一种行为规范,基于接口可以有多种实现类。所以java自身的这种动态代理没有问题。