Java动态代理学习
动态代理类
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
1.Interface InvocationHandler
该接口中仅定义了一个方法:
Object invoke(Object proxy, Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组(无参时设置为null)。
这个抽象方法在代理类中动态实现。
2.Proxy
该类即为动态代理类,作用类似于上文例子中的ProxySubject,其中主要包含如下内容:
protected Proxy(InvocationHandler h): 构造函数,用于给内部的invocation handler赋值。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) : loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) :返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在Subject接口中声明过的方法)。
动态代理类说明
所谓Dynamic Proxy是这样一种class:
它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。
你当然可以把该class的实例当作这些interface中的任何一个来用。
当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口。每一个动态代理类都会有一个与之关联的invocation handler。
真正的调用是在invocation handler的invoke()方法里完成的。
动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke()方法。
2.创建被代理的类以及接口。
3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建一个代理。
4.通过代理调用方法。
动态代理例子1:
首先定义抽象角色和真实角色类:
public interface Subject { public void request(); }
public class RealSubject implements Subject { @Override public void request() { System.out.println("From real subject!"); } }
之后定义一个DynamicSubject类:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象。 * 该类实现了invoke()方法,该方法中的method.invoke()其实就是调用被代理对象的将要执行的方法, * 方法参数sub表示该方法从属于sub。 * 通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法 * */ public class DynamicSubject implements InvocationHandler { //对真实对象的引用 private Object sub; public DynamicSubject(Object obj) { this.sub = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before calling: " + method); //通过反射来调用方法 method.invoke(sub, args); System.out.println("After calling: " + method); return null; } }
使用的时候:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); // 生成代理 // 动态生成一个类(实现了指定的接口),生成类的对象,转换成接口类型 Subject subject = (Subject) Proxy.newProxyInstance(classType .getClassLoader(), realSubject.getClass().getInterfaces(), handler); subject.request(); // 调用方法时,转移给handler接管,由其中的invoke()方法实际完成方法执行 System.out.println(subject.getClass());// 打印出:class $Proxy0 // $Proxy0是在运行期间动态生成的一个类 } }
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
动态代理实现例子2:
这个例子中定义了一个接口:
public interface Foo { public void doAction(); }
这个接口有两个实现类:
public class FooImpl1 implements Foo { @Override public void doAction() { System.out.println("From Implement 1 !"); } } public class FooImpl2 implements Foo { @Override public void doAction() { System.out.println("From Implement 2 !"); } }
定义invocation handler,其中的set方法使得实际对象是可更换的:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class CommonInvocationHandler implements InvocationHandler { private Object target; public CommonInvocationHandler() { } public CommonInvocationHandler(Object obj) { this.target = obj; } public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } }
使用:
import java.lang.reflect.Proxy; public class Demo { public static void main(String[] args) { CommonInvocationHandler handler = new CommonInvocationHandler(); Foo f = null; handler.setTarget(new FooImpl1()); f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler); f.doAction(); System.out.println("----------------------------"); handler.setTarget(new FooImpl2()); f.doAction(); } }
程序运行后输出:
From Implement 1 !
----------------------------
From Implement 2 !
动态代理实现例子3:
1、BookFacade.java
public interface BookFacade { public void addBook(); }
2、BookFacadeImpl.java
public class BookFacadeImpl implements BookFacade { @Override public void addBook() { System.out.println("增加图书方法。。。"); } }
3、BookFacadeProxy.java
-
package net.battier.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * JDK动态代理代理类 * * @author student * */ public class BookFacadeProxy implements InvocationHandler { private Object target; /** * 绑定委托对象并返回一个代理类 * @param target * @return */ public Object bind(Object target) { this.target = target; //取得代理对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷) } @Override /** * 调用方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; System.out.println("事物开始"); //执行方法 result=method.invoke(target, args); System.out.println("事物结束"); return result; } }
4、TestProxy.java
-
package net.battier.test; import net.battier.dao.BookFacade; import net.battier.dao.impl.BookFacadeImpl; import net.battier.proxy.BookFacadeProxy; public class TestProxy { public static void main(String[] args) { BookFacadeProxy proxy = new BookFacadeProxy(); BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl()); bookProxy.addBook(); } }
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
1、BookFacadeCglib.java
-
package net.battier.dao; public interface BookFacade { public void addBook(); }
2、BookCadeImpl1.java
-
package net.battier.dao.impl; /** * 这个是没有实现接口的实现类 * * @author student * */ public class BookFacadeImpl1 { public void addBook() { System.out.println("增加图书的普通方法..."); } }
3、BookFacadeProxy.java
-
package net.battier.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 使用cglib动态代理 * * @author student * */ public class BookFacadeCglib implements MethodInterceptor { private Object target; /** * 创建代理对象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回调方法 enhancer.setCallback(this); // 创建代理对象 return enhancer.create(); } @Override // 回调方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("事物开始"); proxy.invokeSuper(obj, args); System.out.println("事物结束"); return null; } }
4、TestCglib.java
package net.battier.test; import net.battier.dao.impl.BookFacadeImpl1; import net.battier.proxy.BookFacadeCglib; public class TestCglib { public static void main(String[] args) { BookFacadeCglib cglib=new BookFacadeCglib(); BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1()); bookCglib.addBook(); } }