Java 23种设计模式之代理模式
一:简介
设计模式分为三大类:
创立型模式,共五种:工厂办法模式(已讲过)、形象工厂模式(已讲过)、单例模式(已讲过)、建造者模式(已讲过)、原型模式(已讲过)。
结构型模式,共七种:适配器模式(已讲过)、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板办法模式、观察者模式(已讲过)、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
代理模式(Proxy)是通过代理对象拜访指标对象,这样能够在指标对象根底上加强额定的性能,如增加权限,访问控制和审计等性能
。
Java代理分为动态代理和动静代理和Cglib代理
二:动态代理
动态代理在应用时,须要定义接口或者父类,被代理对象与代理对象一起实现雷同的接口或者是继承雷同父类.
接口类AdminService 接口
这是一个指标
public interface AdminService { //我定义一个用户服务权限接口 //定义了一个更新办法 void update(); //定义了一个查找办法,查找返回数据 Object find();}
实现类AdminServiceImpl
/**动态接口的实现类*/public class AdminServiceImpl implements AdminService{ @Override public void update() { System.out.println("我曾经更新了零碎"); } @Override public Object find() { System.out.println("我曾经查看了零碎"); return new Object(); }}
最要害的代理类AdminServiceProxy ,动态代理也要实现目标接口AdminService
public class AdminServiceProxy implements AdminService { private AdminService adminService; public AdminServiceProxy(AdminService adminService) { this.adminService= adminService; } @Override public void update() { System.out.println("判断用户是否有权限进行update操作"); adminService.update(); System.out.println("记录用户执行update操作的用户信息、更改内容和工夫等"); } @Override public Object find() { System.out.println("判断用户是否有权限进行find操作"); System.out.println("记录用户执行find操作的用户信息、查看内容和工夫等"); return adminService.find(); }}
调用
//创立一个指标对象 AdminService adminService=new AdminServiceImpl(); //构建一个代理对象 AdminServiceProxy proxy= new AdminServiceProxy(adminService); //调用更新 proxy.update(); System.out.println("============================="); proxy.find() //后果System.out: 判断用户是否有权限进行update操作System.out: 我曾经更新了零碎System.out: 记录用户执行update操作的用户信息、更改内容和工夫等System.out: =============================System.out: 判断用户是否有权限进行find操作System.out: 记录用户执行find操作的用户信息、查看内容和工夫等System.out: 我曾经查看了零碎
总结:
动态代理模式在不扭转指标对象的前提下,实现了对指标对象的性能扩大。
有余:动态代理实现了指标对象的所有办法,一旦指标接口减少办法,代理对象和指标对象都要进行相应的批改,减少保护老本。
三:JDK 动静代理
为解决动态代理对象必须实现接口的所有办法的问题,Java给出了动静代理,动静代理具备如下特点:
1.Proxy对象不须要implements接口;
2.Proxy对象的生成利用JDK的Api,在JVM内存中动静的构建Proxy对象。须要应用java.lang.reflect.Proxy类的
/** * Returns an instance of a proxy class for the specified interfaces * that dispatches method invocations to the specified invocation * handler. * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @param h the invocation handler to dispatch method invocations to * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces */static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler invocationHandler );
办法,办法参数阐明:
a.ClassLoader loader:指定以后target对象应用类加载器,获取加载器的办法是固定的;
b.Class<?>[] interfaces:target对象实现的接口的类型,应用泛型形式确认类型
c.InvocationHandler invocationHandler:事件处理,执行target对象的办法时,会触发事件处理器的办法,会把以后执行target对象的办法作为参数传入。
接口类AdminService 接口
这是一个指标
public interface AdminService { //我定义一个用户服务权限接口 //定义了一个更新办法 void update(); //定义了一个查找办法,查找返回数据 Object find();}
实现类AdminServiceImpl ,这是一个指标对象的实现类
/**动态接口的实现类*/public class AdminServiceImpl implements AdminService{ @Override public void update() { System.out.println("我曾经更新了零碎"); } @Override public Object find() { System.out.println("我曾经查看了零碎"); return new Object(); }}
动静代理和动态代理区别,动静代理不必实现目标接口,通过Jdk中的newProxyInstance,动静生成,动静代理
package com.ruan.mygitignore;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;public class AdminServiceDynamicProxy { //保护一个指标对象 private Object target; //保护一个事件处理,执行target对象的办法时,会触发事件处理器的办法,会把以后执行target对象的办法作为参数传入。 private InvocationHandler invocationHandler; public AdminServiceDynamicProxy(Object target, InvocationHandler invocationHandler) { this.target = target; this.invocationHandler = invocationHandler; } public Object getPersonProxy(){ //target.getClass().getClassLoader():获取指标对象的应用类加载器 //target.getClass().getInterfaces():获取指标对象实现的接口的类型 //invocationHandler,是构造函数传入的,那咱们就要想怎么创立这个InvocationHandler Object obj= Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),invocationHandler); return obj; }
下面说了invocationHandler须要咱们传入那咱们如何生成它了AdminServiceInvocation 实现接口InvocationHandler
package com.ruan.mygitignore;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class AdminServiceInvocation implements InvocationHandler { private Object target; public AdminServiceInvocation(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("判断用户是否有权限进行操作"); //最要害的就是这个invoke(target):办法的注入 Object obj =method.invoke(target); System.out.println("记录用户执行操作的用户信息、更改内容和工夫等"); return obj; }}
调用
//办法一 System.out.println("============ 办法一 =============="); //构建指标对象 AdminService adminService=new AdminServiceImpl(); System.out.println("代理的指标对象:" + adminService.getClass()); //创立事件处理 AdminServiceInvocation adminServiceInvocation=new AdminServiceInvocation(adminService); //构建代理对象 AdminServiceDynamicProxy adminServiceDynamicProxy = new AdminServiceDynamicProxy(adminService,adminServiceInvocation); //获取代理的指标对象 AdminService proxy= (AdminService) adminServiceDynamicProxy.getPersonProxy(); System.out.println("代理对象:" + proxy.getClass()); Object obj = proxy.find(); System.out.println("find 返回对象:" + obj.getClass()); System.out.println("----------------------------------"); proxy.update(); //后果System.out: ============ 办法一 ==============2021-07-26 16:43:24.602 12407-12407/com.ruan.mygitignore I/对象:class com.ruan.mygitignore.AdminServiceImplSystem.out: 代理对象:class $Proxy1System.out: 判断用户是否有权限进行操作System.out: 我曾经查看了零碎System.out: 记录用户执行操作的用户信息、更改内容和工夫等System.out: find 返回对象:class java.lang.ObjectSystem.out: ----------------------------------System.out: 判断用户是否有权限进行操作System.out: 我曾经更新了零碎System.out: 记录用户执行操作的用户信息、更改内容和工夫等 //办法二,是把getPersonProxy()办法拿到里面间接调用,不分装了 System.out.println("============ 办法二 =============="); AdminService target = new AdminServiceImpl(); AdminServiceInvocation invocation = new AdminServiceInvocation(target); AdminService proxy2 = (AdminService)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),invocation); Object obj2 = proxy2.find(); System.out.println("find 返回对象:" + obj2.getClass()); System.out.println("----------------------------------"); proxy2.update(); //办法三,连InvocationHandler也不封装了,间接调用时候应用传递 System.out.println("============ 办法三 =============="); final AdminService target3 = new AdminServiceImpl(); AdminService proxy3 = (AdminService) Proxy.newProxyInstance(target3.getClass().getClassLoader(), target3.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("判断用户是否有权限进行操作"); Object obj = method.invoke(target3, args); System.out.println("记录用户执行操作的用户信息、更改内容和工夫等"); return obj; } }); Object obj3 = proxy3.find(); System.out.println("find 返回对象:" + obj3.getClass()); System.out.println("----------------------------------"); proxy3.update();
四:Cglib代理
Cglib不能在Android中应用
JDK动静代理要求target对象是一个接口的实现对象,如果target对象只是一个独自的对象,并没有实现任何接口,这时候就会用到Cglib代理(Code Generation Library),即通过构建一个子类对象,从而实现对target对象的代理,因而指标对象不能是final类(报错),且指标对象的办法不能是final或static(不执行代理性能)。
Cglib依赖的jar包
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.10</version> </dependency>
Cglib对于Android来说,Android生成的.dex文件而不是.class文件须要另外实现形式
指标对象类AdminCglibService.java
public class AdminCglibService { public void update() { System.out.println("批改管理系统数据"); } public Object find() { System.out.println("查看管理系统数据"); return new Object(); }}
代理类AdminServiceCglibProxy.java
public class AdminServiceCglibProxy implements MethodInterceptor { private Object target; public AdminServiceCglibProxy(Object target) { this.target = target; } //给指标对象创立一个代理对象 public Object getProxyInstance() { //工具类 Enhancer en = new Enhancer(); //设置父类 en.setSuperclass(target.getClass()); //设置回调函数 en.setCallback(this); //创立子类代理对象 return en.create(); } public Object intercept(Object object, Method method, Object[] arg2, MethodProxy proxy) throws Throwable { System.out.println("判断用户是否有权限进行操作"); Object obj = method.invoke(target); System.out.println("记录用户执行操作的用户信息、更改内容和工夫等"); return obj; }}
调用
AdminCglibService target = new AdminCglibService(); AdminServiceCglibProxy proxyFactory = new AdminServiceCglibProxy(target); AdminCglibService proxy = (AdminCglibService)proxyFactory.getProxyInstance(); System.out.println("代理对象:" + proxy.getClass()); Object obj = proxy.find(); System.out.println("find 返回对象:" + obj.getClass()); System.out.println("----------------------------------"); proxy.update(); //后果 代理对象:class com.lance.proxy.demo.service.AdminCglibService$$EnhancerByCGLIB$$41b156f9判断用户是否有权限进行操作查看管理系统数据记录用户执行操作的用户信息、更改内容和工夫等find 返回对象:class java.lang.Object----------------------------------判断用户是否有权限进行操作批改管理系统数据记录用户执行操作的用户信息、更改内容和工夫等
END:当你感觉你达到了高峰,其实可能才达到另一座山峰的谷底