前言
对于上篇文章说的动态代理是JDK的动态代理,使用动态代理解决了静态代理耦合度高、代码冗余、不易维护等问题,但是JDK的动态代理也是有局限性的,JDK动态代理必须有接口,才可以通过反射进行动态代理,如果没有接口怎么办?铛铛铛!~CGlib闪亮登场。
CGlib特点
- 对于不使用接口的业务类,无法使用JDK动态代理
- CGlib采用非常底层的字节码技术,可以为一个类创建子类,解决无接口代理问题
CGlib怎么用
既然不需要抽象接口了,直接搞一个实例类:
package com.bean.ReflectDemo2;
public class ProductDao {
public void save() {
System.out.println("保存用户...");
}
public void delete() {
System.out.println("删除用户...");
}
public void find() {
System.out.println("查找用户...");
}
public void update() {
System.out.println("更新用户...");
}
}
四个方法:增删改查,假设我们需要对find方法进行增强,在执行find方法之前进行权限校验,也就是所谓的AOP。
首先我们需要写一个代理类:MyCglibProxy
package com.bean.ReflectDemo2;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyCglibProxy implements MethodInterceptor {
private ProductDao productDao;
public MyCglibProxy(ProductDao productDao) {
this.productDao = productDao;
}
public Object createProxy() {
//1.创建核心类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(productDao.getClass());
//3.设置回调
enhancer.setCallback(this);
//4.生成代理
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if ("find".equals(method.getName())){
System.out.println("权限校验=============");
Object o1 = methodProxy.invokeSuper(o, objects);
return o1;
}
return methodProxy.invokeSuper(o,objects);
}
}
可以看出来,跟JDK的动态代理其实差不多,只是名字有不同,各别调用有不同,还是比较好理解的,再来看一下测试类:
package com.bean.ReflectDemo2;
public class Demo {
public static void main(String[] args) {
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
proxy.find();
}
}
跟JDK动态代理其实差不多,而且更方便了。
总结
1、程序中应该优先对接口创建代理,便于程序解耦维护
2、标记为final的方法,不能被代理,因为无法被覆盖
- JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
- CGlib是针对目标类生产子类,因此类或方法,不能使用final的
- Spring只支持方法连接点,不支持属性连接点