Spring 中的 aop
1, Spring 中的 aop 注入到容器中的 对象是动态代理对象,代理的类型分为jdkProxy 和 CglibAopProxy 线程 其中被代理的对象是一个实体类且没有实现接口的时候,使用的是 CglibAopProxy 代理,当被代理的对象是实现一个接口的时候,使用的是jdkProxy
动态代理生成类.jpg
在启动类上添加的注解 使用的是@EnableAspectJAutoProxy(proxyTargetClass = true),参数也可以决定生成的代理类型
java动态代理、 cglib动态代理 底层实现? 实现都是通过Java,操作字节码,创建的对象 Java > class > jvm
为什么Java动态代理必须是接口?因为动态代理实现类默认 继承了 proxy ,在Java中类是单继承,所以必须是实现接口
为什么Java动态代理必须是实现接口.jpg
jdk实现动态代理的核心必须实现InvocationHandler 接口
public class Test9 implements InvocationHandler {
/**
* 自定义接口类
*/
static interface Car{
void runing();
}
/**
* 静态内部类
*/
static class Bus implements Car{
@Override
public void runing() {
System.out.println("bus ~~~ run~~");
}
}
/**
* 静态内部类
*/
static class Taxi implements Car{
@Override
public void runing() {
System.out.println("Taxi ~~~ run~~");
}
}
/**
* 代理对象
*/
private Object target;
/**
* 获取到代理对象
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
/**
* 实现代理
* @param proxy 代理对象
* @param method 代理方法
* @param args 代理参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理前的代码~~~~");
// 执行此方法前后可以进行自定义业务处理
Object invoke = method.invoke(target, args);
// 执行此方法后
return invoke;
}
public static void main(String[] args) {
// 执行jdkproxy
Test9 test9 = new Test9();
Car car = (Car) test9.getInstance(new Bus());
car.runing();
}
}
在上述代码中 Test9 类相当于一个 代理对象,想要成为代理对象需要实现 InvocationHandler 接口 . 然后重写 接口必须的getInstance() 方法
此外需要一个自定义的属性 用于 重写 invoke方法中的代理方法
getInstance() 方法中 三个参数分别代表了 proxy 代理对象,
method 代理方法, args 代理参数
当代理方法被阻塞的时候 .会重复 执行前面 代理类方法被调用前的代码.
在引入 CGLib前需要在 pom文件中加入以下依赖
java代码实现如下
/**
* 自定义接口类
*/
static class Car{
void runing(){
System.out.println("this car is run ~~~~");
}
}
static class CGLib implements MethodInterceptor {
private Object target;
// 自定义实现getInstance 方法
public Object getInstance(Object target){
this.target=target;
// 使用增强器类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass( this.target.getClass());
// 设置回调
enhancer.setCallback(this);
return enhancer.create();
}
// 重写接口定义的方法
@Override
public Object intercept(Object o,
Method method,
Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法前的处理~~~~");
// 进行代理的类的方法调用
Object result = methodProxy.invokeSuper(o, objects);
// 还可以进行剩下的业务逻辑处理
return result;
}
}
public static void main(String[] args) {
Car instance = (Car) new CGLib().getInstance(new Car());
instance.runing();
}
CGLib 的区别是通过enhancer 将代理类设置为被代理类的子类 来实现代理.因此 被代理类不能被final 关键字修饰,否则无法代理类无法继承,
如果被代理类 是final 修饰 则被报错
Cannot subclass final class com.example.userinfo.test.Test10$Car
lombok 的实现是反射嘛?
lombok 和反射完全没有关系, 反射是 程序在运行期间的一种自省 ,而lombok 实际上是在编译期间就完成了.
动态代理和静态代理的区别