//对所有方法代理 //System.out.println ("请检查类型.......befor:"+method.getName()); Object o = method.invoke(list,args);
return o ;
}
public static Object factory(Object o )...{ Class c = o.getClass();
//用真实的对象来构造代理对象 return Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),new ArrayListProxy(o)); } }class TestDProxy...{ public static void main(String[] args)...{ ArrayList al = new ArrayList(); List pro = (List)ArrayListProxy.factory(al);
public static void main(String[] args) { UserDAO daoImpl = new UserDAOMySQLImpl(); //拿到实现被代理类(UserDAO)的实现类的对象 UserDAO dao = (UserDAO)getInstance(daoImpl);
User user = new User("001"); dao.addUser(user); } /** * * @param dao 被代理的对象 * @return 返回的是实现了被代理对象的对象(JDK $Proxy0) */ public static Object getInstance(UserDAO dao) { Object o = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{UserDAO.class}, new LogHandler(dao)); return o; }
} 程序运行结果:开始记录日志,添加用户方法开始执行... connect to MySQL DataBase... id=001的用户信息成功添加到数据库表中... 开始记录日志,添加用户方法执行结束... 假如现在还有一个需求,想记录下在添加用户成功之后,记录添加用户方法的运行时间 使用代理之后,就可以不用改变原来的代码,直接扩展一个记录时间的方法处理器就可以了,比如说叫 TimeHandler,是不是更加灵活了假如说现在还有一个需求,想在方法执行的前后加上权限的检查,同样可以直接扩展出一个SecureHandler来处理方法调用。假如说还有这样一个需求:想在方法中加上Transaction(事物)的控制,是不是只需要一个控制事物的处理器,TransactionHandler,,,假如,假如,假如,,,,,,,,,,,,,,,你能想到什么,动态代理就能代理什么,,,功能很是强大。。 不知道LZ是不是有点明白什么是动态代理了。也晚了,也饿了,吃饭去了,有问题继续提啊,。。
1、代理的意思:本来应该自己做的事情,因为没有某种原因不能直接做,只能请别人代理做。被请的人就是代理。比如春节买票回家,由于没有时间,只能找票务中介来买,这就是代理模式。2、以下的例子将简单的模拟代理模式 比如一个信息管理系统,有的用户有浏览的权限,有的用户有修改和编辑的权限,有的用户除了以上的权限,还有删除的权限。(1) 最普通的做法: public class ViewAction {
public void doAction(){ String permission = "view"; if(permission.equals(Constants.PRIMISSION_VIEW)){ System.out.println("you could view information"); //........做view的动作 } } } 其他的动作和浏览的动作差不多。但这样做有两个缺点:(一)它把权限的控制的执行的动作放在一起,两者的功能混在一起,造成了维护和修改的不方便。不满足单一职责原则。(二)客户端调用的是具体的实现类,造成了扩展和运行时调用的困难,不满足依赖颠倒原则(最下面补充说明)。(2)初步代理 因此对以上的类做了重新设计,通过代理实现。和买车票一样,代理类必须先检测权限,再执行动作。修改后的密码如下。 接口类(首先设计一个接口,满足依赖颠倒原来): public interface IAction { public void doAction(); } 动作执行类(相当于买车票的动作),动作的真正执行者: public class ViewAction implements IAction { public void doAction() { System.out.println("you could view the information"); //............做view的动作 } } 代理类(ViewActionProxy )除了做了客户要做的doAction()动作,还做了权限的判断。而ViewAction只做了核心动作,满足了单一原则。 public class ActionProxy implements IAction { private ViewAction viewAction = new ViewAction(); public void doAction() { if(Permission.getPermission(userid).equals (Constants.PERMISSION_VIEW)){ viewAction.doAction(); } } } 总之,客户段通过调用这个代理类执行动作,这个代理类通过将权限判断和具体的动作执行分开。实现了单一原则。代理类又叫委派,即代理类并没有亲自执行,而是委派给另一个类来执行。ProxyViewAction并没有亲自执行,而是给ViewAction执行。 再看看ViewActionProxy,他不仅依赖于抽象接口IAction,而且依赖具体类ViewAction。这样对系统的扩展性很不好。因为我们还有add,delete,update动作等。(1)我们可以为每个动作都写一个代理类,可是每个代理类都做相同的动作:先进行权限的判断,再执行具体的动作。所以我们对ViewAction具体类再一次抽象,使得代理类(ViewActionProxy)只依赖于接口IAction,而不依赖具体类ViewAction。(3)代理改进:将代理类脱离动作的具体执行类。 要实现这个功能,必须让代理类的具体实现去掉(private ViewAction viewAction = new ViewAction();),而让代理类的使用者,再使用的时候提供具体的实现类,这个就是依赖注入。 public class ViewActionProxy implements IAction { private IAction action ; public void setAction(IAction action) { this.action = action; }
public static Set getSetProxy(final Set s) {
return (Set) Proxy.newProxyInstance
(s.getClass().getClassLoader(),
new Class[] { Set.class },
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
return method.invoke(s, args);
}
});
}
}
比如:Ibm买电脑,代理商就可以也买电脑还送鼠标。
IBM.买电脑(){
买电脑操作();
}代理商.买电脑(){
送鼠标操作();
IBM.买电脑();
}spring 的事务有用这个,LZ可以去学习下
你可以GOOGLE一下.
//假设做一个ArrayList 的 添加提示的功能。 就是 在调用它的add方法的时候 输出一句 请检查类型.import java.lang.reflect.InvocationHandler;
import java.lang.reflect.*;
import java.util.*;
class ArrayListProxy implements InvocationHandler...{
Object list ;
ArrayListProxy(Object list )...{
this.list = list;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable...{
if(method.getName().equals("add"))...{
//对特定方法代理
System.out.println ("请检查类型.......befor:"+method.getName());
}
//对所有方法代理
//System.out.println ("请检查类型.......befor:"+method.getName());
Object o = method.invoke(list,args);
return o ;
}
public static Object factory(Object o )...{
Class c = o.getClass();
//用真实的对象来构造代理对象
return Proxy.newProxyInstance(c.getClassLoader(),c.getInterfaces(),new ArrayListProxy(o));
}
}class TestDProxy...{
public static void main(String[] args)...{
ArrayList al = new ArrayList();
List pro = (List)ArrayListProxy.factory(al);
pro.add("aaa");
System.out.println (pro.size());
}
}
更多关于代理 : http://blog.csdn.net/caoyinghui1986/archive/2008/05/16/2450221.aspx
假如有一个用户的实体类叫User
package org.chinasoft.proxy.test;/**
* 用户实体类
* @author lilei
*
*/
public class User {
private String id;
public User(String id) {
this.id = id;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
}}
实现对实体类User类的数据管理,UserDAO
package org.chinasoft.proxy.test;public interface UserDAO {
//可以有很多的方法(del,update,query...)
void addUser(User user);}
不同UserDAO的实现:UserDAOMySQLImpl,UserDAOOracleImplpackage org.chinasoft.proxy.test;public class UserDAOMySQLImpl implements UserDAO {
public void addUser(User user) {
// connect to MySQL,insert a row recoder
System.out.println("connect to MySQL DataBase...");
System.out.println("id=" + user.getId() + "的用户信息成功添加到数据库表中...");
}}
UserDAOOracleImpl:package org.chinasoft.proxy.test;public class UserDAOOracleImpl implements UserDAO { public void addUser(User user) {
//connect to Oracle,insert a row recoder
System.out.println("connect to Oracle DataBase...");
System.out.println("id=" + user.getId() + "的用户信息成功添加到数据库表中...");
}}
现在假如说,有这样一个需求,就是说想在把用户添加到数据库调用addUser方法之前和之后记录下当前操作的
的日志(比如某某用户被添加到数据库等等)LogHandler类,功能是负责控制任意被代理对象中任意方法的执行过程,简单说具体到本类中功能就是记录方法
运行前后的日志
package org.chinasoft.proxy.test;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class LogHandler implements InvocationHandler {
//持有被代理对象的引用(此引用可以有外部灵活制定的)
private Object target;
public LogHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始记录日志,添加用户方法开始执行...");
method.invoke(target, args);
System.out.println("开始记录日志,添加用户方法执行结束...");
return null;
}}
测试类:TestProxypackage org.chinasoft.proxy.test;import java.lang.reflect.Proxy;public class TestProxy {
public static void main(String[] args) {
UserDAO daoImpl = new UserDAOMySQLImpl();
//拿到实现被代理类(UserDAO)的实现类的对象
UserDAO dao = (UserDAO)getInstance(daoImpl);
User user = new User("001");
dao.addUser(user);
} /**
*
* @param dao 被代理的对象
* @return 返回的是实现了被代理对象的对象(JDK $Proxy0)
*/
public static Object getInstance(UserDAO dao) {
Object o = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{UserDAO.class},
new LogHandler(dao));
return o;
}
}
程序运行结果:开始记录日志,添加用户方法开始执行...
connect to MySQL DataBase...
id=001的用户信息成功添加到数据库表中...
开始记录日志,添加用户方法执行结束...
假如现在还有一个需求,想记录下在添加用户成功之后,记录添加用户方法的运行时间
使用代理之后,就可以不用改变原来的代码,直接扩展一个记录时间的方法处理器就可以了,比如说叫
TimeHandler,是不是更加灵活了假如说现在还有一个需求,想在方法执行的前后加上权限的检查,同样可以直接扩展出一个SecureHandler来处理方法调用。假如说还有这样一个需求:想在方法中加上Transaction(事物)的控制,是不是只需要一个控制事物的处理器,TransactionHandler,,,假如,假如,假如,,,,,,,,,,,,,,,你能想到什么,动态代理就能代理什么,,,功能很是强大。。
不知道LZ是不是有点明白什么是动态代理了。也晚了,也饿了,吃饭去了,有问题继续提啊,。。
public void doAction(){
String permission = "view";
if(permission.equals(Constants.PRIMISSION_VIEW)){
System.out.println("you could view information"); //........做view的动作
}
}
} 其他的动作和浏览的动作差不多。但这样做有两个缺点:(一)它把权限的控制的执行的动作放在一起,两者的功能混在一起,造成了维护和修改的不方便。不满足单一职责原则。(二)客户端调用的是具体的实现类,造成了扩展和运行时调用的困难,不满足依赖颠倒原则(最下面补充说明)。(2)初步代理 因此对以上的类做了重新设计,通过代理实现。和买车票一样,代理类必须先检测权限,再执行动作。修改后的密码如下。 接口类(首先设计一个接口,满足依赖颠倒原来): public interface IAction {
public void doAction();
} 动作执行类(相当于买车票的动作),动作的真正执行者: public class ViewAction implements IAction {
public void doAction() {
System.out.println("you could view the information");
//............做view的动作
}
} 代理类(ViewActionProxy )除了做了客户要做的doAction()动作,还做了权限的判断。而ViewAction只做了核心动作,满足了单一原则。 public class ActionProxy implements IAction {
private ViewAction viewAction = new ViewAction();
public void doAction() {
if(Permission.getPermission(userid).equals
(Constants.PERMISSION_VIEW)){
viewAction.doAction();
}
}
} 总之,客户段通过调用这个代理类执行动作,这个代理类通过将权限判断和具体的动作执行分开。实现了单一原则。代理类又叫委派,即代理类并没有亲自执行,而是委派给另一个类来执行。ProxyViewAction并没有亲自执行,而是给ViewAction执行。 再看看ViewActionProxy,他不仅依赖于抽象接口IAction,而且依赖具体类ViewAction。这样对系统的扩展性很不好。因为我们还有add,delete,update动作等。(1)我们可以为每个动作都写一个代理类,可是每个代理类都做相同的动作:先进行权限的判断,再执行具体的动作。所以我们对ViewAction具体类再一次抽象,使得代理类(ViewActionProxy)只依赖于接口IAction,而不依赖具体类ViewAction。(3)代理改进:将代理类脱离动作的具体执行类。 要实现这个功能,必须让代理类的具体实现去掉(private ViewAction viewAction = new ViewAction();),而让代理类的使用者,再使用的时候提供具体的实现类,这个就是依赖注入。 public class ViewActionProxy implements IAction {
private IAction action ;
public void setAction(IAction action) {
this.action = action;
}
public void doAction() {
if(Permission.getPermission(userid).
equals(Constants.PERMISSION_VIEW)){
action.doAction();
}
}
} 这样我们能就将所有使用了IAction接口的具体类都通过这个代理类来代理。比如AddAction、DeleteAction、 UpdateAction都可以用这个代理类来代理。(4)动态代理:没有实现接口的类的某些方法也可以使用代理。分别添加增加add,delete,update方法,可是每个方法体内都做相同的动作:先进行权限的判断,再执行具体的动作。 如果我们没办法将所有的类抽象出一个统一的接口,我们可能有多个接口。但是按照上面的方法,每个代理都必须为每个接口写一个相应的代理类。没有统一的接口情况下,对一些零散的对象的某些动作使用代理模式。 动态代理的核心是InvocationHandler,要实现动态代理,就必须实现这个接口。这个接口的委派任务是在public Object invoke(Object proxy, Method method, Object[] args)方法中实现的。invoke的主要流程如下: ...........................//在调用核心动作前的作一些动作。 m.invoke(obj, args); //调用核心动作。 ............................//在调用核心动作后的做一些动作。 我们看到动态代理是通过反射机制来调用核心功能m.invoke(obj, args); 这个反射机制使得我们不依赖任何一个具体的接口,而是依赖具体的类。动态代理类的具体实现如下: public class ActionProxy implements InvocationHandler {
private Object action;
public ActionProxy(Object action){
this.action = action;
}
public static Object getInstance(Object action){
return Proxy.newProxyInstance(
action.getClass().getClassLoader(),
action.getClass().getInterfaces(),
new ActionProxy(action)); //自动生成相应的代理类,且类里面有个变量是ActionProxy对象,当客户端调用这个代理类的方法时候,代理类会调用它的ActionProxy 变量的invoke方法,因此每次调用了代理类,就可以在方法执行前和方法执行后加入特定的执行内容(事务或日志等)。
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result;
System.out.println("befor method:"+method.getName());
result = method.invoke(action, args);
System.out.println("after method:"+method.getName());
return result;
}
} 代理类必须实现InvocationHandler接口,getInstance()方法获得代理类的实例(实现了IAction接口)的对应代理,invoke方法实现了简单的代理方法。客户段代码如下: public class TrasasactionTest {
public static void main(String[] args) {
IAction action = (IAction) ActionProxy.getInstance(new ViewAction());
action.doAction();
}
} 由上得出,代理对于接口的依赖转移到客户端,代理不必再实现特定的接口。因此ActionProxy也可以用于任何的接口。 ITestService service = (ITestService ) ActionProxy.getInstance(new TestServiceImpl());
service .doTest();//只要TestServiceImpl实现ITest,就可以。(5)在委派前的动作和委派后的动作在不同的代理类不用,可是代理类的生成和其他的内容都是相同的。所以我们可以用Template模式对代理类进行进一步的优化。 生成代理类的基类的代码如下:public abstract class BaseProxy implements InvocationHandler {private Object target;public Object getTarget() {
return target;
}public BaseProxy(Object target){
this.target = target;
}public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result;
doBefore();
result = method.invoke(target, args);
doAfter();
return result;
}
public abstract void doBefore();
public abstract void doAfter();
}代理类基类的具体实现如下: public class ProxyImpl extends BaseProxy {
public ProxyImpl(Object target) {
super(target);
} //委派前的动作
public void doAfter() {
System.out.println("do before method");
} //委派后的动作
public void doBefore() {
System.out.println("do after method");
}
} 因此,在OOP中,doBefore(),核心动作,doAfter()可能这3个动作在所有的类中都存在,但是doBefore,doAfter的内容都是相同的,而核心动作确实不相同的。因此把doBefore和doAfter提取出来,共同设计,这是AoP的基础。AoP的一个重要特点是找出哪些方法需要执行doBefore和doAfter,哪些不用。