定义:为另一个对象提供一个替身或占位符以控制这个对象的访问。
转载:http://haolloyin.blog.51cto.com/1177454/333257/
Java设计模式(七) Spring AOP JDK动态代理 vs. Cglib
1、JDK自带的动态代理(代理必须实现接口)
理解
动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- //抽象主题类,这里不能用abstract抽象类,一定要是interface
- interface AbstractSubject {
- public abstract void request();
- }
- // 真实主题类,即被代理类
- class RealSubject implements AbstractSubject {
- public void request() {
- System.out.println("RealSubject's request() ...");
- }
- }
- // 动态代理类,实现InvocationHandler接口
- class DynamicProxy implements InvocationHandler {
- // 被代理类的实例
- Object obj = null;
- // 将被代理者的实例传进动态代理类的构造函数中
- public DynamicProxy(Object obj) {
- this.obj = obj;
- }
- /**
- * 覆盖InvocationHandler接口中的invoke()方法
- *
- * 更重要的是,动态代理模式可以使得我们在不改变原来已有的代码结构
- * 的情况下,对原来的“真实方法”进行扩展、增强其功能,并且可以达到
- * 控制被代理对象的行为,下面的before、after就是我们可以进行特殊
- * 代码切入的扩展点了。
- */
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- /*
- * before :doSomething();
- */
- Object result = method.invoke(this.obj, args);
- /*
- * after : doSomething();
- */
- return result;
- }
- }
- // 测试类
- public class Client {
- public static void main(String[] args) {
- // 被代理类的实例
- AbstractSubject realSubject = new RealSubject();
- // 获得被代理类的类加载器,使得JVM能够加载并找到被代理类的内部结构,以及已实现的interface
- ClassLoader loader = realSubject.getClass().getClassLoader();
- // 获得被代理类已实现的所有接口interface,使得动态代理类的实例
- Class<?>[] interfaces = realSubject.getClass().getInterfaces();
- // 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序
- InvocationHandler handler = new DynamicProxy(realSubject);
- /*
- * loader : 被代理类的类加载器
- * interfaces :被代理类已实现的所有接口,而这些是动态代理类要实现的接口列表
- * handler : 用被代理类的实例创建动态代理类的实例,用于真正调用处理程序
- *
- * return :返回实现了被代理类所实现的所有接口的Object对象,即动态代理,需要强制转型
- */
- //获得代理的实例
- AbstractSubject proxy = (AbstractSubject) Proxy.newProxyInstance(
- loader, interfaces, handler);
- proxy.request();
- //打印出该代理实例的名称
- System.out.println(proxy.getClass().getName());
- }
- }
DesignPattern.proxy.dynamicProxy.$Proxy0
为什么JDK动态代理只能代理实现了接口的类
可以打印出代理类的字节码,从该类的声明中可以看到,继承了Proxy类,并实现了目标接口。验证了上文中的论点——所有生成的动态代理类都是Proxy类的子类。同时也解释了为什么JDK动态代理只能代理实现了接口的类——Java不支持多继承,代理类已经继承了Proxy类,无法再继承其它类。
2.cglib(是直接修改字节码,可以用继承实现代理)
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
public interface BookFacade {
public void addBook();
}
/**
* 这个是没有实现接口的实现类
*
* @author student
*
*/
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 使用cglib动态代理
*
* @author student
*
*/
public class BookFacadeCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
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 obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
}
}
import net.battier.dao.impl.BookFacadeImpl1;
import net.battier.proxy.BookFacadeCglib;
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}