java23中设计模式之代理模式
1.staicproxy ---静态代理
一).代理模式(proxy pattern) 核心作用:
1).通过代理,控制对对象的访问!
2).可以详细控制访问某个对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理
二).应用场景
1).安全代理:屏蔽对真实脚色真实访问
2).远程代理: 通过代理类处理远程方法调用(RMI)
3).延迟加载:先加载轻量级的代理对象,真正需要在加载真实对象
三).分类
1).静态代理(静态定义代理类)
2).动态生成代理类(动态生成代理类)
--JDK自带的动态代理
--javaassist字节码操作库实现
--Cglib 类库实现
--ASM (底层使用指令,可维护性较差)
package cn.sxt.service; public interface UserService { public void add(); public void update(); public void delete(); public void search(); }
package cn.sxt.service; public class UserServiceImpl implements UserService { @Override public void add() { //公共的业务----日志,安全,权限,缓存,事务等等 //A.log();---分离的思想--纸质阅读器;osgi--java模块开发-spring--osgi System.out.println("增加用户"); } @Override public void update() { System.out.println("修改用户"); } @Override public void delete() { System.out.println("删除用户"); } @Override public void search() { System.out.println("查询用户"); } }
package cn.sxt.service; public class UserServiceProxy implements UserService{ private UserService userService; public UserServiceProxy(UserService userService) { super(); this.userService = userService; } public UserServiceProxy() { super(); } @Override public void add() { log("add"); userService.add(); } @Override public void delete() { //日志,安全,缓存,事务,异常处理等 log("delete"); userService.delete(); } @Override public void search() { log("search"); userService.search(); } public void update() { log("update"); userService.update(); } public void log(String methodName){ System.out.println("执行"+methodName+"方法"); } }
package cn.sxt.service; public class Test { public static void main(String[] args) { UserServiceProxy proxy=new UserServiceProxy(new UserServiceImpl()); proxy.add(); proxy.update(); proxy.delete(); proxy.search(); } } /*执行add方法 增加用户 执行update方法 修改用户 执行delete方法 删除用户 执行search方法 查询用户 */
2.dynamicproxy动态代理
一)动态代理相比静态代理的优点
1).抽象角色中(接口)声明的 所以方法都被转移到调用处理器一个集中的地方处理,这样,我们可以更加灵活
和统一的处理众多的方法
2)开发框架中应用场景:
--stuts2 中拦截器的实现
--数据库连接池关闭处理
--hibernate 中延迟加载的实现
-- mybatis中实现拦截器插件
-- Aspect的实现
--spring中AOP 的实现
日志拦截和声明式实物处理
--web service RMI 远程方法调用
二).JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
三).Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
四).Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
version1
package cn.sxt.dynamicproxy; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; import cn.sxt.service.UserService; import cn.sxt.service.UserServiceImpl; public class Client { public static void main(String[] args) { System.out.println("userService+++++++++++++++++++++++++++++++"); UserService userService = new UserServiceImpl(); ProxyInovationHandler pih = new ProxyInovationHandler(userService); UserService proxy = (UserService)pih.getProxy(); proxy.delete(); System.out.println("list+++++++++++++++++++++++++++++++"); ProxyInovationHandler ph1 = new ProxyInovationHandler(new ArrayList()); List list = (List)ph1.getProxy(); list.add(1); System.out.println(list.get(0)); } } /*userService+++++++++++++++++++++++++++++++ 执行delete方法 前置 删除用户 后置 list+++++++++++++++++++++++++++++++ 执行add方法 前置 后置 执行get方法 前置 后置 1 */
package cn.sxt.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInovationHandler implements InvocationHandler{ private Object target;//目标对象--真实对象 public ProxyInovationHandler() { super(); } public ProxyInovationHandler(Object i) { super(); this.target = i; } public Object getProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * proxy是代理类 * method 代理类的调用处理程序的方法对象 * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行"+method.getName()+"方法"); System.out.println("前置"); Object result = method.invoke(target, args); System.out.println("后置"); return result; } }
package cn.sxt.service; public interface UserService { public void add(); public void update(); public void delete(); public void search(); }
package cn.sxt.service; public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加用户"); } @Override public void update() { System.out.println("修改用户"); } @Override public void delete() { System.out.println("删除用户"); } @Override public void search() { System.out.println("查询用户"); } }
version 2
package com.ndqn.proxy; public interface Start { /** * 面谈 */ void confer(); /** * 签合同 */ void signContract(); /** * 订票 */ void bookTicket(); /** * 唱歌 */ void sing(); /** * 收钱 */ void collectMoney(); }
package com.ndqn.proxy; public class RealStar implements Start { @Override public void bookTicket() { System.out.println("RealStar.bookTicket()"); } @Override public void collectMoney() { System.out.println("RealStar.collectMoney()"); } @Override public void confer() { System.out.println("RealStar.confer()"); } @Override public void signContract() { System.out.println("RealStar.signContract()"); } @Override public void sing() { System.out.println("RealStar(周杰伦sing()"); } }
package com.ndqn.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class StarHandle implements InvocationHandler { Start realStart; public StarHandle(Start realStart) { super(); this.realStart = realStart; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object = null; System.out.println("真正的方法执行前!"); System.out.println("面谈,签合同,预付款,订机票"); if(method.getName().equals("sing")){ object = method.invoke(realStart, args); } System.out.println("真正的方法执行后!"); System.out.println("收尾款"); return object; } }
package com.ndqn.proxy; /** * 妯℃嫙鍔ㄦ�鐢熸垚鐨勪唬鐞嗙殑缁撴瀯 * @author Administrator * */ public class ProxyStar implements Start { StarHandle handler; public ProxyStar(StarHandle handler) { super(); this.handler = handler; } public void bookTicket() { // handler.invoke(this,当前方法 , args); } public void collectMoney() { // handler.invoke(this,当前方法 , args); } public void confer() { // handler.invoke(this,当前方法, args); } public void signContract() { // handler.invoke(this,当前方法 , args); } public void sing() { // handler.invoke(this,当前方法 , args); } }
package com.ndqn.proxy; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { Start realStar = new RealStar(); StarHandle handler = new StarHandle(realStar); Start proxy = (Start) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Start.class}, handler); proxy.sing(); } }
3.带有AOP的动态代理模式类图:
从上图中,可以看出有两个相对独立的模块(Subject和InvocationHandler)。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。然而,通知Advice从另一个切面切入,最终在上层模块就是Client耦合,完成逻辑的封装。
代码清单如下
抽象主题或者接口:
package com.yemaozi.proxy.dynamic_aop; public interface Subject { public void doSomething(String str); //...可以多个逻辑处理方法。。。 }
package com.yemaozi.proxy.dynamic_aop; public class RealSubject implements Subject{ public void doSomething(String str) { //do something... System.out.println("do something..." + str); } }
package com.yemaozi.proxy.dynamic_aop; //通知接口及定义、 public interface IAdvice { public void exec(); }
package com.yemaozi.proxy.dynamic_aop; public class BeforeAdvice implements IAdvice { //在被代理的方法前来执行,从而达到扩展功能。 public void exec() { System.out.println("前置通知被执行!"); } }
package com.yemaozi.proxy.dynamic_aop; public class AfterAdvice implements IAdvice { //在被代理的方法后来执行,从而达到扩展功能。 public void exec() { System.out.println("后置通知被执行!"); } }
package com.yemaozi.proxy.dynamic_aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler { //被代理的对象 private Subject realSubject; //通过MyInvocationHandler的构造方法将被代理对象传递过来。 public MyInvocationHandler(Subject realSubject){ this.realSubject = realSubject; } //执行被代理类的方法。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在执行方法前,执行前置通知。 IAdvice beforeAdvice = new BeforeAdvice(); beforeAdvice.exec(); Object result = method.invoke(this.realSubject, args); //在执行方法后,执行后置通知。 IAdvice afterAdvice = new AfterAdvice(); afterAdvice.exec(); //前置通知,和后置通知,都是要看具体实际的业务需求来进行添加。 return result; } }
package com.yemaozi.proxy.dynamic_aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class DynamicProxy { /** * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler handler) * loader: * 一个ClassLoader对象,定义了由哪个ClassLoader对象,来对生产的代理进行加载。 * interfaces: * 一个Interfaces数组,表示我将要给我所代理的对象提供一组什么样的接口, * 如果提供一组接口给它,那么该代理对象就宣称实现了该接口,从而可以调用接口中的方法。 * 即,查找出真是主题类的所实现的所有的接口。 * handler: * 一个InvocationHandler对象,表示当我这个动态代理对象在调用方法时,会关联到该InvocationHandler对象。 * 该InvocationHandler与主题类有着关联。 */ public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, InvocationHandler handler){ @SuppressWarnings("unchecked") T t = (T) Proxy.newProxyInstance(classLoader, interfaces, handler); return t; } }
package com.yemaozi.proxy.dynamic_aop; import java.lang.reflect.InvocationHandler; public class AOPClient { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler handler = new MyInvocationHandler(realSubject); ClassLoader classLoader = realSubject.getClass().getClassLoader(); Class<?>[] interfaces = realSubject.getClass().getInterfaces(); Subject proxySubect = DynamicProxy.newProxyInstance(classLoader, interfaces, handler); proxySubect.doSomething("这是一个Dynamic AOP示例!!!"); } } 执行结果: 前置通知被执行! do something...这是一个Dynamic AOP示例!!! 后置通知被执行!
动态代理在现在用的是非常的多的,如像Spring AOP ,DBCP连接池,AspectJ等。。。
4. Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
package com.bdqn.ulist; /** *这个是没有实现接口的实现类 * * @author admin * */ public class BookCadeImpl { public void add() { System.out.println("This is add service"); } public void delete(int id) { System.out.println("This is delete service:delete " + id ); } }
package com.bdqn.ulist; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 使用cglib动态代理 */ public class BookFacadeCglib implements MethodInterceptor { Object target; public Object getInstance(Object target){ this.target=target; Enhancer enhancer=new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); } //回调方法 public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable { System.out.println("事务开始"); Object ob=proxy.invokeSuper(obj, arg); System.out.println("事务结束"); return ob; } }
package com.bdqn.ulist; import java.beans.Introspector; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; public class TestCglib { public static void main(String[] args) { BookFacadeCglib interceptor=new BookFacadeCglib(); BookCadeImpl cadeImpl=(BookCadeImpl) interceptor.getInstance(new BookCadeImpl()); cadeImpl.add(); cadeImpl.delete(2); } }