上文: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 {@Overridepublic 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() {@Overridepublic 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{@Overridepublic 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内部的所有方法都能应用该代理方法@Overridepublic 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.newProxyInstancepublic 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自身的这种动态代理没有问题。