一、静态代理
package com.yt.manager.proxy; /** * @Description: 要代理的接口 * @ClassName: Service * @Project: spring-aop * @Author: zxf * @Date: 2011-6-2 */ public interface Service { public void outPut(); public void putOut(); public void outPut1(String v); }
package com.yt.manager.proxy; /** * @Description: 要代理接口的实现类 * @ClassName: ServiceImpl * @Project: spring-aop * @Author: zxf * @Date: 2011-6-2 */ public class ServiceImpl implements Service { @Override public void outPut() { // TODO Auto-generated method stub System.out.println("to run outPut method.............."); } @Override public void putOut() { // TODO Auto-generated method stub System.out.println("to run putOut method.............."); } public void outPut1(String v) { System.out.println("参数内容:" + v); } }
package com.yt.manager.proxy; /** * @Description: 静态代理类 * @ClassName: ServiceManagerImplProxy * @Project: base-info * @Author: zxf * @Date: 2011-5-19 */ public class ServiceManagerImplProxy implements Service { private Service service; public ServiceManagerImplProxy(Service service) { this.service = service; } @Override public void outPut() { // 在调用方法前调用验证方法 this.checkSecurity(); this.service.outPut(); } @Override public void putOut() { // 在调用方法前调用验证方法 this.checkSecurity(); this.service.putOut(); } @Override public void outPut1(String v) { // 在调用方法前调用验证方法 this.checkSecurity(); this.service.outPut1(v); } public void checkSecurity() { System.out.println("------------代理前要做的处理-----------------------"); } }
package com.yt.manager.proxy; /** * 调用代理测试类 * * @Description: * @ClassName: TestProxy * @Project: base-info * @Author: zxf * @Date: 2011-5-19 */ public class TestProxy { public static void main(String[] args) { Service s = new ServiceImpl(); Service serviceImp = new ServiceManagerImplProxy(s); serviceImp.outPut(); } }
可以看出静态代理类有一个很不爽的缺点:当如果接口加一个方法(把上面所有的代码的注释给去掉),所有的实现类和代理类里都需要做个实现。这就增加了代码的复杂度。动态代理就可以避免这个缺点。
二、动态代理
动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
动态代理类只能代理接口,代理类都需要实现InvocationHandler类,实现invoke方法。该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
1、java.lang.reflect.proxy
proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
newProxyInstance()
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
java.lang.reflect.InvocationHandler,
InvocationHandler 是代理实例的调用处理程序 实现的接口。
invoke()
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
(详见api文档)
2、
(1)、要代理实现类的接口
package com.yt.manager.proxy; public interface Service { public void outPut(); public void putOut(); public void outPut1(String v); }
(2)、要代理的实现类
package com.yt.manager.proxy; public class ServiceImpl implements Service { @Override public void outPut() { // TODO Auto-generated method stub System.out.println("to run outPut method.............."); } @Override public void putOut() { // TODO Auto-generated method stub System.out.println("to run putOut method.............."); } public void outPut1(String v) { System.out.println("参数内容:" + v); } }
(3)、代理类
package com.yt.manager.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * Java中的动态代理(作用:日志处理,事物处理,一些过滤器,拦截器之类的处理等AOP。 ) * 1、我们要有一个接口和一个实现该接口的实现类,而这个实现类就是我们要代理的对象。 * 2、我们要写一个要在代理类的方法执行时,能够做额外工作的类,而该类必须实现InvocationHandler接口。为什么要实现接口呢? * 因为代理类的实例在调用实现类的方法的时候,不会真正调用实现类的方法,而是转到这个类的invoke方法,在这个方法中我们进行 * 处理调用默认方法前的处理。 * 3、在要用代理类的实例去调用实现类的方法的时候,使用以下代码: * Service serviceImp = (Service) new SecurityHandler().newProxy(new ServiceImpl()); * serviceImp.outPut(); * * @author zxf * */ public class SecurityHandler implements InvocationHandler { private Object originalObject; // 将欲代理的对象传入,返回一个代理对象 public Object newProxy(Object obj) { this.originalObject = obj; // 三个参数,第一个是欲代理对象的类加载器,第二个是得到这个类的接口集合,第三个参数是一个handler return (Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this)); } /** * @param proxy 要代理的实现类 * @param method 要代理的实现类的方法 * @param args 要代理的实现类的方法的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { checkSecurity(); // 若方法名以out开头则调用下面逻辑 if (method.getName().startsWith("out")) { System.out.println("--------以拦截的方法!--------"); // 调用欲代理对象的相应方法 method.invoke(originalObject, args); } else { // 若不是需要拦截的方法则正常执行方法 method.invoke(originalObject, args); } return null; } public void checkSecurity() { System.out.println("--------在调用要代理类的方法前做的处理----------"); } }
(4)、测试类
package com.yt.manager.proxy; /** * 调用代理测试类 * @Description: * @ClassName: TestProxy * @Project: base-info * @Author: zxf * @Date: 2011-5-19 */ public class TestProxy { public static void main(String[] args) { Service serviceImp = (Service) new SecurityHandler().newProxy(new ServiceImpl()); serviceImp.outPut(); serviceImp.putOut(); serviceImp.outPut1("zhouxufeng"); } }