先来讲说代理模式(静态代理):
其为23种设计模式之一,属于结构型模式,其主要思想是经过一个代理对象来代替真实对象来响应client的调用或请求。静态代理要求代理类与真实类实现一个共同的接口,这样代理对象才能在“型”上代替真实对象。类图以下:
java
一个经过代理模式来代理并加强真实对象的简单示例:node
//定义代理类与真实类的公共接口 public interface Subject { public void operation(); } //真实主题,即被代理对象的类 public class RealSubject implements Subject { public void operation() { System.out.println("执行业务处理... ..."); } } //使用代理对象来代替真实对象,并对真实对象中的处理方法进行加强 public class ProxySubject implements Subject { private Subject real; //持有真实对象 public ProxySubject(Subject subject){ //constructor,注入真实的被代理的对象 this.real = subject; } public void operation() { //对被代理的对象方法进行加强 beforeOperation(); real.operation(); //真实主题中的方法 afterOperation(); } private void beforeOperation(){ //加强处理 System.out.println("业务预先处理..."); } private void afterOperation(){ //加强处理 System.out.println("业务善后处理..."); } } //测试main函数 public class Main { public static void main(String[] args) { Subject real = new RealSubject(); Subject proxy = new ProxySubject(real); proxy.operation(); //在实际使用时,操做代理对象来代替真实对象 } }
代理模式应用很是普遍,在各类框架中也能找到其应用。例如在DAO(data access object)模式中:
DAO接口:声明要对DB进行哪些操做
DAOImpl类:实现DAO接口,定义对DB的具体操做
DAOProxy类:代理DAOImpl,并额外进行DB的打开、关闭操做
DAOFactory:建立代理对象的工厂
spring
然而静态代理并非很灵活,如上例,就只能代理和加强实现了Subject接口的真实类,不能代理任意类型的真实类。设计模式
下面来看动态代理:
动态代理便可以在运行时生成代理,其更加灵活,Java提供了Proxy类和InvocationHandler接口两个工具来实现动态代理功能。动态代理的流程以下图:
api
使用java api中静态方法:Proxy.newProxyInstance()来生成对象:
Proxy.newProxyInstance(classloader, interface, handler) => proxy对象
classloader:类加载器,用于将动态生成的代理类的字节码加载到JVM中,通常就使用被代理类的加载器
interface:被代理类实现的接口,故此,当被代理中存在非接口的方法时,应该就没法被动态加强
handler:InvocationHandler接口的实现类,在handler.invoke()中实现对被代理类接口方法进行加强
框架
动态代理示例:dom
//真实类的接口型 public interface Subject { public void operation(); //定义了真实类的操做 } //真实类: public class RealSubject implements Subject { //实现接口,完成业务处理 public void operation() { System.out.println("执行业务处理... ..."); } } //加强工具:注意此工具没有实现Subject接口,彻底是一个独立的工具方法单元,通常被称为拦截器 public class EnhanceTool { public void beforeOperation(){ //加强处理 System.out.println("业务预先处理..."); } public void afterOperation(){ //加强处理 System.out.println("业务善后处理..."); } } //***动态代理的核心之处*** public class MyInvocationHandler implements InvocationHandler { private Object real; public void setReal(Object real){ //持有被代理的对象 this.real = real; } //InvocationHandler接口中的方法,在此方法中对被代理类接口方法加强 public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { EnhanceTool tool = new EnhanceTool(); tool.beforeOperation(); //加强工具方法 Object result = method.invoke(real, args); //经过反射调用真实对象中的方法 tool.afterOperation(); //加强工具方法 return result; } } //生成代理对象的工厂: public class MyProxyFactory { public static Object getProxy(Object real) throws Exception{ MyInvocationHandler handler = new MyInvocationHandler(); handler.setReal(real); //Proxy中的静态方法:输入参数(类加载器,被代理类的接口,InvocationHandler的实现类),返回代理对象 return Proxy.newProxyInstance(real.getClass().getClassLoader(), real.getClass().getInterfaces(), handler); } } //测试main: public static void main(String[] args) throws Exception { Subject real = new RealSubject(); Subject proxy = (Subject) MyProxyFactory.getProxy(real); proxy.operation(); }
经过上面的示例可以看到,动态代理更加的灵活,其加强方法的类彻底是一个独立于代理过程的单元,只是单纯的被调用,能随时被替换。且像生成代理对象或调用真实对象方法的具体操做,都由Java API来提供。可以很是好的实现解耦。函数
接下来是AOP(aspect orient program),下面的示例使用动态代理来模拟spring中的AOP。根据xml文件中的配置信息来肯定动态代理的加强流程和方法。(在时间切面上插入加强方法,来增长总体程序的功能)。工具
//AOP接口,即动态代理中被代理类实现的接口 public interface AOP { public void saveMoney(); public void getMoney(); } //被代理类,实现接口中的方法 public class AOPImpl implements AOP { public void saveMoney() { System.out.println("正在存钱..."); } public void getMoney() { System.out.println("正在取钱..."); } } //动态代理中的handler: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Map; public class AOPHandler implements InvocationHandler { private Object obj; private boolean flag; public AOPHandler(Object obj){ this.obj = obj; } public void setFlag(Map<String, String> config) { //根据解析xml获得的map,设置标志位,进而影响invoke中的执行流程 if (config == null) { flag = false; } else { if (config.containsKey("transaction") && "true".equalsIgnoreCase(config.get("transaction"))) { flag = true; } else { flag = false; } } } //关键之处,接口方法,当经过代理对象调用真实类中的方法时,实际调用的是下面的invoke方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (flag) { //根据配置信息来决定是否执行 doBefore(); } Object result = method.invoke(obj, args); //根据反射调用被代理类中的方法 if (flag) { //根据配置信息来决定是否执行 doAfter(); } return result; } private void doBefore() { //加强处理,或叫时间切面长插入的方法 System.out.println("Transaction start..."); } private void doAfter() { System.out.println("Transaction commit..."); } } //经过DOM( Document Object Model)来解析xml配置文件 //将xml配置文件中的配置信息,解析为<key, value>对的形式放入map中 import java.io.InputStream; import java.util.HashMap; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class XMLUtil { public static Map<String, String> parseXML() throws Exception { Map<String, String> result = new HashMap<String, String>(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); InputStream in = XMLUtil.class.getClassLoader().getResourceAsStream("config.xml"); Document document = db.parse(in); Element root = document.getDocumentElement(); NodeList xmlNodes = root.getChildNodes(); //将整个xml文件转换为NodeList形式 for (int i = 0; i < xmlNodes.getLength(); i++) { //遍历NodeList取得配置信息 Node config = xmlNodes.item(i); //Node封装了配置的节点名与值的信息 if (null != config && config.getNodeType() == Node.ELEMENT_NODE) { String nodeName = config.getNodeName(); if ("transaction".equals(nodeName)) { //Node.getNodeName() String textContent = config.getTextContent(); //Node.getTextContext() result.put("transaction", textContent); //将配置信息放入map中 } } } return result; } } //调用解析方法,将xml文件的解析结果放入map中 import java.util.Map; public class JVMCache { private static Map<String, String> config; //储存解析xml获得的配置信息 public synchronized static Map<String, String> getConfig() throws Exception { if (config == null) { config = XMLUtil.parseXML(); } return config; } } /src/config.xml配置文件 <?xml version="1.0" encoding="UTF-8"?> <config> <transaction>true</transaction> //此处为改成fals,则handler.invoke()中的两个加强方法就不会执行 </config> //测试主函数: public class Client { public static void main(String[] args) throws Exception { AOPImpl impl = new AOPImpl(); AOPHandler handler = new AOPHandler(impl); //在handler中,持有一个被代理对象 handler.setFlag(JVMCache.getConfig()); //将xml配置文件解析出来的map传入handler //获取代理对象 AOP aop = (AOP) Proxy.newProxyInstance(AOPImpl.class.getClassLoader(), new Class<?>[] {AOP.class}, handler); aop.saveMoney(); aop.getMoney(); } }