设计模式之代理模式

一 Proxy 代理

代理:字面上讲,在别人的授权范围内,代别人处理。也就是说,不直接和你要访问的人或者对象打交道,而是和他的代理人或者代理对象打交道。比如说常见的代理服务器和微商代理。用代理服务器举例,你访问代理服务器,代理服务器再从真实服务器获取数据或者资源返给你。这期间,你是不知道代理服务器背后的真实服务器的,所以你也不会真实服务器进行交互。这样做的好处有利于保护真实服务器的安全。     

代理模式:为真实对象提供一个代理,然后外部通过访问代理对象,从而实现对真实对象的访问。

代理分类:

虚拟代理:根据需要创建开销很大的对象,在对象只有在需要的时候才会被真正创建。

保护代理:控制对真实对象的保护。

根据代理类是否是在程序运行过程中产生的,区分为静态代理和动态代理

二 静态代理

静态代理:代理类在程序运行之前就已经存在了,即我们手动编写的代理类。

特点:

# 既然代理类要进行代理真实对象,就需要保持和被代理对象(真实对象)相同的接口

# 代理类需要持有被代理,在构造代理类的时候,就需要指定他代理的是谁,真正的操作还是北代理对象去做,代理类也就做一些辅助性质的工作

public interface Subject {

       void execute();

       void invoke();

}

public class RealSubject implements Subject {

       public void execute() {

              System.out.println("执行execute方法...");

       }



       public void invoke() {

              System.out.println("执行invoke方法...");

       }

}



public class ProxySubject implements Subject {

       private RealSubject real;

       public ProxySubject(RealSubject real) {

              this.real = real;

       }

       public void execute() {

              this.real.execute();

       }

       public void invoke() {

              this.real.invoke();

       }

}

三 动态代理

动态代理:当代理类需要程序的运行过程中才能产生,这个代理就属于动态代理,常见的动态代理:

JDK 动态代理:只能代理实现了某接口的类,如果是继承的父类的方式,则不能代理

CGLib动态代理:可以对继承的类进行代理的方式,这种方式不是JDK自带的,是属于第三方,内部封装了一个java字节码生成框架ASM

3.1 JDK动态代理

public interface Subject {

       void execute();

       void invoke();

}

public class RealSubject implements Subject {

       public void execute() {

              System.out.println("执行execute方法...");

       }



       public void invoke() {

              System.out.println("执行invoke方法...");

       }

}



public class DynamicProxyFactory implements InvocationHandler {



       private Object target;



       private Object getProxyInterface(Object target) {

              this.target = target;

              ClassLoader classLoader = this.target.getClass().getClassLoader();

              Class<?>[] interfaces = this.getClass().getInterfaces();

              Object proxy = Proxy.newProxyInstance(classLoader, interfaces, this);

              return proxy;

       }



       /**

        * 之所以可以被调用,是因为产生的代理类$proxy0实现了InvocationHandler和继承了Proxy

        * 那么$Proxy中代理的接口方法,会先调用父类的Proxy的InvocationHandler接口的invoke方法

        */

       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {



              return method.invoke(this.target, args);

       }

}

特点:

# 代理需要实现InvocationHandler接口,因为代理类封装后的接口方法会调用InvocationHandler的invoke方法

# 通过Proxy.newProxyInstance方法产生代理实例

# 只能代理实现了某个接口的类

内部原理:

其实就是通过反射:构造器调用newInstance方法,创建代理实例

3.2 CGLib动态代理

CGLib:Code Generation Library的缩写。它的底层通过字节码处理框架ASM,可以直接产生二进制    class文件,也可以在类被加载到JAVA虚拟机以前,改变类行为。

3.2.1 创建代理

CGLib使用Enhancer创建代理,创建代理有2种方式:

方式一:使用Enhancer对象来创建

/** 通过Enhancer的对象来创建动态代理类 */

public class CGLibProxy2 implements MethodInterceptor {



       private static final Logger logger = Logger.getLogger(CGLibProxy2.class);



       public Object getProxyInstance(Object obj) {

              return Enhancer.create(obj.getClass(), this);

       }



       @SuppressWarnings("unchecked")

       public <T> T getProxy(Class<T> clazz) {

              Enhancer enhancer = new Enhancer();

              enhancer.setSuperclass(clazz);

              enhancer.setCallback(this);

              return (T)enhancer.create();

       }



       public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

              logger.info("调用CGLibProxy2方法:"+methodProxy.getSignature().getName());

              Object result = methodProxy.invokeSuper(obj, args);

              logger.info("结束CGLibProxy2方法:"+methodProxy.getSignature().getName());

              return result;

       }

}

方式二:使用Enhancer的静态方法创建,底层还是通过第一种方式创建的。

/** 直接用Enhancer的静态方法生成 */

public class CGLibProxy1 implements MethodInterceptor {



       private static final Logger logger = Logger.getLogger(CGLibProxy1.class);



       public Object getProxyInstance(Object obj) {



              return Enhancer.create(obj.getClass(), this);

       }



       @SuppressWarnings("unchecked")

       public <T> T getProxy(Class<T> clazz) {

              return (T)Enhancer.create(clazz, this);

       }



       public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

              logger.info("调用CGLibProxy1方法:"+methodProxy.getSignature().getName());

              Object result = methodProxy.invokeSuper(obj, args);

              logger.info("结束CGLibProxy1方法:"+methodProxy.getSignature().getName());

              return result;

       }

}

我们需要注意的是:

# 如果被代理的对象的无参构造私有,将无法被代理,因为Enhancer需要根据被代理类无参构造来创建代理

# 如果被代理的类是final,也就是无法继承,或者方法final无法被重写,那么对应的类或者方法也无法被代理(CGLib是基于继承的)

# Enhancer调用create方法创建代理的时候,可以使用无参的create犯法,他创建会根据被代理类的无参构造来创建,比如:

enhancer.create();

如果希望使用待参数的构造方法进行初始化,你可以create方法中指定构造参数类型和参数值。比如:

enhancer.create(new Class<?>[]{String.class,Integer.class}, new Object[]{"nicky",24});

3.2.2 CGLib的拦截器

CGLib除了比JDK更效率之外,他还可以进行过滤,即我可以针对不同方法产生不同的代理效果,换句话说,不同方法交给不同的代理类进行代理。我们可以Enhancer设置CallbackFilter进行过滤,示例代码如下:

public class CGLibProxy3 {

       private static Callback[] callbacks = {new CGLibProxy1(), new CGLibProxy2()};

       @SuppressWarnings("unchecked")

       public <T> T getProxy(Class<T> clazz) {

              Enhancer enhancer = new Enhancer();

              enhancer.setSuperclass(clazz);

              // 将回调数组设置到Enhancer,下面会根据算法选择不同的回调,从而针对不同方法获取不同的代理类

              enhancer.setCallbacks(callbacks);

              enhancer.setCallbackFilter(new CallbackFilter() {

                     // 通过过滤算法,返回要使用的代理类的下标,从而使得可以在控制方法选用不同的代理更加方便一点

                     public int accept(Method method) {

                            String methodName = method.getName();

                            return "execute".equals(methodName) ? 1 : 0;

                     }

              });

              return (T)enhancer.create();

       }

}

代理模式是一种结构型设计模式,它提供一个代理对象来代表另一个对象。在代理模式中,有一个被称为实际对象(Subject)和一个被称为代理对象(Proxy)的中介,代理对象持有实际对象的引用,并且可以控制对实际对象的访问。代理模式的主要目的是在不修改原始对象的情况下,为原始对象添加额外的逻辑处理。 代理模式分为多种类型,如远程代理、虚拟代理、保护代理等,它们各自有不同的应用场景: - 远程代理:为远程对象提供一个本地代表。 - 虚拟代理:根据需要创建开销大的对象,通过虚拟代理控制访问这些对象的过程。 - 保护代理:控制对原始对象的访问权限,例如进行权限检查。 代理模式的优点包括: 1. 能够控制对真实对象的访问,并在访问前后添加额外的逻辑。 2. 可以通过代理对象实现延迟加载,即在实际需要时才创建真实对象。 3. 增强了对真实对象的封装,并且可以避免对真实对象的重复引用。 在C#中实现代理模式通常涉及以下步骤: 1. 定义一个接口或抽象类,声明真实对象和代理对象需要实现的方法。 2. 实现真实对象的类,按照接口或抽象类的要求实现具体方法。 3. 实现代理类,它同样实现接口或抽象类,并在方法中持有真实对象的引用,通过调用真实对象的方法来执行所需的操作,同时可以添加额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫言静好、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值