代理模式是比较常见的一种模式,我们平常接触的比较多,比如正向代理和反向代理。
正向代理的代理服务器是和客户端的网络在一起,由代理服务器转发请求和接受结果,比如有的公司的服务器,会过滤掉对外部网络的访问请求;反向代理的代理服务器接受来自客户端的请求,决定讲请求转发给哪个内部服务器进行处理,反向代理的服务器也可能会过滤掉一些不安全的请求,或者不符合验证条件的请求。
所以代理模式的主要目的是控制对象的访问。
《java与模式》中代理模式有两种实现方式:一种是静态的实现方式,一种是利用jdk的动态的实现方式。
1. 静态的实现方式
示意性代码:
package com.javadesignpattern.Proxy.Static; public abstract class Subject { abstract public void request(); }
package com.javadesignpattern.Proxy.Static; public class RealSubject extends Subject{ @Override public void request() { // TODO Auto-generated method stub System.out.println(RealSubject.class + ": request method"); } }
package com.javadesignpattern.Proxy.Static; public class ProxySubject extends Subject { private Subject subject; public ProxySubject(Subject subject) { this.subject = subject; } public ProxySubject() { } public void preRequest() { System.out.println(ProxySubject.class + ": ProxySubject function"); } public void postRequest() { System.out.println(ProxySubject.class + ": postRequest function"); } @Override public void request() { // TODO Auto-generated method stub preRequest(); if(subject == null){ subject = new RealSubject(); } subject.request(); postRequest(); } }
package com.javadesignpattern.Proxy.Static; public class Client { public static void main(String[] args){ Subject subject = new ProxySubject(); subject.request(); System.out.println("************************"); Subject subject2 = new ProxySubject(new RealSubject()); subject2.request(); } }
2. jdk动态代理
实现jdk的动态代理分成几步:
1. 代理类实现InvocationHandler接口,实现invoke方法。
2. Proxy类的newProxyInstance方法,传递三个参数,classloader, interface和InvocationHandler对象实例。
示意性代码:
package com.javadesignpattern.Proxy.Dynamic; public interface UserManager { public void addUser(String userId, String userName); public void delUser(String userId); public String findUser(String userId, String userName); public void modifyUser(String userId, String userName); }
package com.javadesignpattern.Proxy.Dynamic; public class UserManagerImpl implements UserManager{ public void addUser(String userId, String userName) { // TODO Auto-generated method stub System.out.println("UserManagerImpl.addUser()userId-->"+userId); } public void delUser(String userId) { // TODO Auto-generated method stub System.out.println("UserManagerImpl.delUser()userId-->"+userId); } public String findUser(String userId, String userName) { // TODO Auto-generated method stub System.out.println("UserManagerImpl.findUser()userId-->"+userId); return userName ; } public void modifyUser(String userId, String userName) { // TODO Auto-generated method stub System.out.println("UserManagerImpl.modifyUser()userId-->"+userId); } }
package com.javadesignpattern.Proxy.Dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.text.SimpleDateFormat; public class LoggerHandler implements InvocationHandler{ Object target; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin time:" +getTime()); try{ Object result = method.invoke(target, args); System.out.println("success time:" +getTime()); }catch(Exception e){ e.printStackTrace(); System.out.println("failed time:" +getTime()); } return null; } public Object newInstance(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } public String getTime(){ SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateTime = tempDate.format(new java.util.Date()); return dateTime; } }
package com.javadesignpattern.Proxy.Dynamic; public class Client { public static void main(String[] args){ LoggerHandler loggerHandle = new LoggerHandler(); UserManager userManager = (UserManager)loggerHandle.newInstance(new UserManagerImpl()); userManager.addUser("001", "Christy"); } }
可以看到jdk的动态代理被代理的对象必须实现接口。好忧桑啊。解决的办法是我们想到spring的cglib实现的动态代理,cglib是针对类(实际上是继承子真实主题)的代理,但是不能代理final的(final的不能继承嘛~)。
---------动态代理的优点:
接口中声明的多有方法都被转移到调用处理器中一个集中的方法中进行处理(invocationhandle:invoke),这样接口数量比较多的时候,我们就可以灵活处理。这是优于静态代理的地方。