Java 中的代理实现方式
当一个对象不适合或者不能被其他对象直接引用时,可以给该对象生成一个代理对象,代理对象具有被代理对象的所有功能,这样其他对象使用代理对象时一样可以达到自己的需求
- 相关:设计模式-代理模式
静态代理
- 使用时需要定义接口或者父类,被代理对象和代理对象一起实现相同的接口或者继承相同的父类。缺点是必须为每个被代理对象生成一个代理对象
动态代理
- 特点
不需要实现接口,代理对象的实现是利用 JDK 的 API,动态的在内存中构建代理对象(需要指定创建代理对象/目标对象实现的接口类型)
JDK 实现
特点
- 面向接口的动态代理(被代理对象必须要实现一个接口)
- 没有接口不可能
- 只能读取到接口上的一些注解
代码
// 代理工厂类
public class DynamicProxyFactory_java {
private Object object;//被代理对象
public DynamicProxyFactory_java(Object object) {
this.object = object;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(
object.getClass().getClassLoader(),
object.getClass().getInterfaces(),//所以这种模式必须实现接口
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前准备...");
Object invoke = method.invoke(object, args);//执行被代理对象的方法
System.out.println("执行后处理...");
return invoke;
}
}
);
}
}
// 在代理工厂的构造方法中传入需要被代理的对象,再通过调用 getProxyInstance() 方法即可获取代理对象
public class Run {
public static void main(String[] args) {
BaseDao baseDao = new UserDao();
BaseDao userDao = (BaseDao) new DynamicProxyFactory_java(baseDao).getProxyInstance();
userDao.add();
System.out.println("代理前对象:" + baseDao.getClass().getName());
System.out.println("代理后对象:" + userDao.getClass().getName());
}
}
CGLIB 实现
CGLIB 动态代理不是 JDK 自带的方式,需要引入第三方 jar 包(cglib-xx.xx.x.jar)
特点
- 面向父类的动态代理,也叫子类代理,通过在内存中构建一个子类对象实现对目标对象功能的扩展
- 有没有接口都可以使用
- 可以读取类上的注解
代码
// 动态代理工厂
public class DynamicProxyFactory_cglib implements MethodInterceptor {
private Object object;//被代理对象
public DynamicProxyFactory_cglib(Object object) {
this.object = object;
}
/**
* 创建代理对象
*/
public Object getProxyInstance() {
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(object.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建对象并返回
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("执行前准备...");
Object invoke = method.invoke(object, args);
System.out.println("执行后处理...");
return invoke;
}
}
// 被代理对象,没有实现任何接口
public class MenuDao {
public void add() {
System.out.println("add Menu");
}
}
// 使用方式
public class Run {
public static void main(String[] args) {
MenuDao dao = new MenuDao();
MenuDao menuDao = (MenuDao) new DynamicProxyFactory_cglib(dao).getProxyInstance();
System.out.println("代理前对象:" + dao.getClass().getName());
System.out.println("代理后对象:" + menuDao.getClass().getName());
menuDao.add();
}
}
Spring AOP 中的实现方式
- 关注 targetClass.isInterface(),判断这个类是不是接口,如果是接口使用 JDK 动态代理进行实现,否则使用 CGLIB 动态代理实现
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
}