软件设计模式-代理模式
阅读数:136 评论数:0
跳转到新版页面分类
架构学
正文
一、代理模式
为另一个对象提供一个替身或占位符以控制对这个对象的访问。被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。
与适配器模式的区别,适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。与装饰者模式的区别,装饰者为了增强功能,代理模式是为了加以控制。
静态代理是在程序运行前就已经存在代理类的字节码文件 |
动态代理在内存中构建,动态生成类字节码,并加载到JVM中。Spring AOP底层,就是动态代理模式的实现。很多框架的RPC调用也是使用的动态代理模式。 |
二、静态代理
静态代理就是程序员在编写代码的时候就已经把代理类的源码写好了,编译后就会生成.class文件(即字节码文件)。
1、示例
// person接口
public interface Person {
//租房
public void rentHouse();
}
// 实现上述接口
public class Renter implements Person{
@Override
public void rentHouse() {
System.out.println("租客租房成功!");
}
}
// 代理类
public class RenterProxy implements Person{
private Person renter;
public RenterProxy(Person renter){
this.renter = renter;
}
@Override
public void rentHouse() {
System.out.println("中介找房东租房,转租给租客!");
renter.rentHouse();
System.out.println("中介给租客钥匙,租客入住!");
}
}
三、Java动态代理
Java动态代理类位于java.lang.reflect包下,InvocationHandler接口和Proxy类是核心。
该接口中仅定义了一个方法
Object:invoke(Object obj,Method method,Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。
该类即为动态代理类。
(1)Protected Proxy(InvocationHandler h)
构造函数,估计用于给内部的h赋值。
(2)Static Class getProxyClass(ClassLoader loader, Class[] interfaces)
获得一个代理类,其中loader是类装载器,interfaces是真正拥有的全部接口的数组。
(3)Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
返回代理类的一个实例,返回后的代理类可以当作被代理类使用。
(1)创建一个实现接口InvocationHandler的类,自定义处理逻辑。
(2)通过Proxy的静态方法newProxyInstance创建一个代理。
(3)通过代理调用方法。
(1)首先定义一个Person接口
public interface Person {
//租房
public void rentHouse();
}
(2)创建被代理的类
public class Renter implements Person{
@Override
public void rentHouse() {
System.out.println("租客租房成功!");
}
}
(3)创建RenterInvocationHandler类,这个类实现了InvocationHandler接口,并持有一个被代理类的对象。
public class RenterInvocationHandler<T> implements InvocationHandler{
//被代理类的对象
private T target;
public RenterInvocationHandler(T target){
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//代理过程中插入其他操作
System.out.println("租客和中介交流");
Object result = method.invoke(target, args);
return result;
}
}
(4)创建动态代理对象
public class ProxyTest {
public static void main(String[] args) {
//创建被代理的实例对象
Person renter = new Renter();
//创建InvocationHandler对象
InvocationHandler renterHandler = new RenterInvocationHandler<Person>(renter);
//创建代理对象,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person renterProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(),new Class<?>[]{Person.class}, renterHandler);
renterProxy.rentHouse();
//也可以使用下面的方式创建代理类对象,Proxy.newProxyInstance其实就是对下面代码的封装
/*try {
//使用Proxy类的getProxyClass静态方法生成一个动态代理类renterProxy
Class<?> renterProxyClass = Proxy.getProxyClass(Person.class.getClassLoader(), new Class<?>[]{Person.class});
//获取代理类renterProxy的构造器,参数为InvocationHandler
Constructor<?> constructor = renterProxyClass.getConstructor(InvocationHandler.class);
//使用构造器创建一个代理类实例对象
Person renterProxy = (Person)constructor.newInstance(renterHandler);
renterProxy.rentHouse();
//
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
}
}
四、CGLIB动态代理
jdk的动态代理需要被代理的类实现接口,如果被代理类没有实现接口,可以使用cglib代理。
cglib代理也叫作子类代理,它通过在内存中构建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,然后加入自己的需要操作,因为使用的是继承的方式,所以不能代理final类。
Spring-core中已经包含了cglib功能。
1、示例
(1)创建被代理类UserService
public class UserService {
public void getName(){
System.out.println("张三!");
}
}
(2)创建代理工厂类ProxyFactory
public class ProxyFactory<T> implements MethodInterceptor {
private T target;
public ProxyFactory(T target) {
this.target = target;
}
// 创建代理对象
public Object getProxyInstance() {
// 1.cglib工具类
Enhancer en = new Enhancer();
// 2.设置父类
en.setSuperclass(this.target.getClass());
// 3.设置回调函数
en.setCallback(this);
return en.create();
}
//拦截方法
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("开始事务...");
// 执行目标对象的方法
Object result = method.invoke(target, args);
System.out.println("提交事务...");
return result;
}
}