引:代理模式(Proxy Pattern)是Java中常用到的一种设计模式。其定义为:为其他对象提供一种代理以控制对这个对象的访问。使用代理模式创建代理对象,让代理对象控制目标对象,如此可以在不改变目标对象的情况下加入额外的功能吗,即扩展目标对象的功能。常见的代理模式有:静态代理、动态代理、Cglib代理。
代理模式一般涉及到的角色有:
RealSubject:委托类,是业务逻辑的具体执行者。Subject是委托类和代理类的接口或父类,里面是普通的业务类型定义。Proxy是代理类,内部含有对委托对象的引用,从而可以操作委托对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。 在代码实现中相当于为一个委托对象realSubject提供一个代理对象proxy,通过proxy可以调用realSubject的部分功能,并添加一些额外的业务处理,同时可以屏蔽realSubject中未开放的接口。
- 静态代理:
需要定义接口或者父类,委托对象与代理对象一起实现相同的接口或者是继承相同父类。静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
/**
* 接口:定义了目标对象的主要功能
*/
public interface Subject {
public void method1();
}
/**
* 目标对象:实现接口
*
*/
public class RealSubject implements Subject {
@Override
public void method1() {
System.out.println("realSubject starts....");
}
}
public class Proxy implements Subject{
private RealSubject subject; //目标对象
public Proxy(RealSubject subject) {
this.subject = subject;
}
@Override
public void method1() {
System.out.println("开始事务...");
subject.method1(); //执行目标对象的方法
System.out.println("提交事务...");
}
//测试
public static void main(String[] args) {
RealSubject subject = new RealSubject();//目标对象
Proxy proxy = new Proxy(subject);//代理对象,把目标对象传给代理对象,建立代理关系
proxy.method1();//执行代理的方法
}
}
- 动态代理
动态代理的对象是利用JDK的API动态的生成的。代理对象不需要实现接口。目标对象一定要实现接口,否则不能用动态代理。动态代理中,代理类是在运行时期生成,相比静态代理,动态代理可以很方便的对委托类的方法进行统一处理,如添加方法调用次数、添加日志功能等等。
/**
* interface
*
*/
public interface Subject {
public void method1();
}
/**
* 委托类
*
*/
public class RealSubject implements Subject {
@Override
public void method1(){
System.out.println("realSubject starts....");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 创建动态代理对象
* 动态代理不需要实现接口,但是需要指定接口类型
*/
public class ProxyFactory{
private Object target; //维护一个目标对象
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务....");
Object returnValue = method.invoke(target, args);
System.out.println("提交事务....");
return returnValue;
}
};
return Proxy.newProxyInstance(loader, interfaces, h);
}
}
/**
* 测试类
*
*/
public class APP {
public static void main(String[] args) {
// 目标对象
Subject target = new RealSubject();
// 代理对象
Subject proxy = (Subject) new ProxyFactory(target).getProxyInstance();
//执行方法
proxy.method1();
}
}
上述ProxyFactory还可以编码如下
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 创建动态代理对象
* 动态代理不需要实现接口,但是需要指定接口类型
*/
public class ProxyFactory implements InvocationHandler{
private Object target; //维护一个目标对象
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象生成代理对象
public Object getProxyInstance(){
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务....");
Object returnValue = method.invoke(target, args);
System.out.println("提交事务....");
return returnValue;
}
}
执行结果:
开始事务....
realSubject starts....
提交事务....
动态代理只需要实现 java.lang.reflect.Proxy类的静态方法newProxyInstance()即可,该方法需要接收三个参数:
- ClassLoader loader,:指定当前目标对象使用类加载器。
- Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型。
- InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。InvocationHandler该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args),第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
- Cglib代理
上述静态代理和动态代理模式都是要求目标对象是实现一个接口或继承父类的目标对象,但是有时候目标对象只是一个单独的对象,此时可以使用以目标对象子类的方式类实现代理——Cglib代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口。它广泛的被许多AOP的框架使用,例如Spring AOP。Spring AOP示例代码中引入
public class RealSubject{
public void method1(){
System.out.println("realSubject starts....");
}
}
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* Cglib子类代理工厂
*
*/
public class CglibProxyFactory implements MethodInterceptor{
private Object target; //维护一个目标对象
public CglibProxyFactory(Object target) {
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("开始事务...");
//执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务...");
return returnValue;
}
}
/**
* 测试类
*
*/
public class APP {
public static void main(String[] args) {
// 目标对象
RealSubject target = new RealSubject();
RealSubject proxy = (RealSubject) new CglibProxyFactory(target).getProxyInstance();
proxy.method1();
}
}
在Spring的AOP编程中:如果加入容器的目标对象有实现接口,用JDK动态代理,如果目标对象没有实现接口,用Cglib代理。