本文转自: http://blog.csdn.net/leon709/article/details/9529307
动态代理应用广泛,spring,Struts等框架很多功能是通过动态代理,或者进一步封装来实现的。
常见的动态代理模式实现有Java API提供的动态代理和第三方开源类库CGLIB动态代理。
Java API提供的动态代理是基于类反射实现的,用到的类有:
java.lang.reflect.InvocationHandler;
java.lang.reflect.Method;
java.lang.reflect.Proxy;
其实现是通过Proxy类的newProxyInstance()方法产生代理对象。自定义动态代理类需要实现InvocationHandler接口,该接口只有一个invoke()方法。
CGLIB是通过生成java 字节码从而动态的产生代理对象,因此需要字节码解析处理的依赖asm类库,字节码动态生成的代理对象实际上是继承了真实主题类的。这种实现方式需要导入cglib和asm的类库。下面用到的例子是cglib-2.2.2.jar, asm-3.3.1.jar。cglib使用了MethodInterceptor,其中的方法是intercept(),这是拦截的概念,很容易就想到了Struts2的拦截器。
比较之下,Java API提供的动态代理需要面向接口,产生代理对象,因此真实主题实现类必须实现了接口才可以。而CGLIB不需要面向接口,可以代理简单类,但由于动态代理对象是继承真实主题实现类的,因此要求真实主题实现类不能是final的。
下面是实现的例子。
首先,为了看到动态代理可以根据不同类动态产生不同代理的效果,我们新建两个接口,及其实现类。
- package leon.aj.dynproxy.target;
-
- public interface Hello {
- public String sayHello(String name);
- }
实现类:
- package leon.aj.dynproxy.target;
-
- public class HelloImpl implements Hello {
- @Override
- public String sayHello(String name) {
- String s = "Hello, "+name;
- System.out.println(this.getClass().getName()+"->"+s);
- return s;
- }
- }
另一接口和实现类:
- package leon.aj.dynproxy.target;
-
- public interface UserDao {
- public boolean login(String username,String password);
- }
- package leon.aj.dynproxy.target;
-
- public class UserDaoImpl implements UserDao {
- @Override
- public boolean login(String username, String password) {
- String user = "("+username+","+password+")";
- System.out.println(this.getClass().getName()+"-> processing login:"+user);
- return true;
- }
- }
应用Java API实现的动态代理类:
- package leon.aj.dynproxy.java;
-
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
-
- public class JavaDynProxy implements InvocationHandler{
- private Object target;
- public Object getProxyInstance(Object target){
- this.target = target;
- return Proxy.newProxyInstance(target.getClass().getClassLoader(),
- target.getClass().getInterfaces(), this);
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- System.out.println("before target method...");
- result = method.invoke(target, args);
- System.out.println("after target method...");
- return result;
- }
- }
测试:
- package leon.aj.dynproxy.java;
-
- import leon.aj.dynproxy.target.Hello;
- import leon.aj.dynproxy.target.HelloImpl;
- import leon.aj.dynproxy.target.UserDao;
- import leon.aj.dynproxy.target.UserDaoImpl;
-
- public class TestJavaProxy {
- public static void main(String[] args) {
- JavaDynProxy proxy = new JavaDynProxy();
- Hello hello = (Hello)proxy.getProxyInstance(new HelloImpl());
- String s = hello.sayHello("Leon");
- System.out.println(s);
-
- UserDao userDao = (UserDao) proxy.getProxyInstance(new UserDaoImpl());
- userDao.login("Leon", "1234");
- System.out.println(userDao.getClass().getName());
- }
- }
下面是采用cglib实现的例子(推荐):
性能方面看其他文章写的是cglib要略高一筹, 因为jdk代理大量使用反射的方式。而反射比较耗费性能,cglib就没有这一个顾虑,他直接就是调用生成的子类的方法。
- package leon.aj.dynproxy.cglib;
-
- import java.lang.reflect.Method;
-
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
-
- public class CglibProxy implements MethodInterceptor {
- private Object target;
-
- public Object getProxyInstance(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 target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
- System.out.println("before target method...");
- Object result = proxy.invokeSuper(target, args);
- System.out.println("after target method...");
- return result;
- }
- }
测试类:
- package leon.aj.dynproxy.cglib;
-
- import leon.aj.dynproxy.target.Hello;
- import leon.aj.dynproxy.target.HelloImpl;
- import leon.aj.dynproxy.target.UserDaoImpl;
-
- public class TestCiglib {
- public static void main(String[] args) {
- CglibProxy proxy = new CglibProxy();
- Hello hello = (Hello) proxy.getProxyInstance(new HelloImpl());
- System.out.println(hello.sayHello("Leon"));
- UserDaoImpl userDao = (UserDaoImpl) proxy.getProxyInstance(new UserDaoImpl());
- userDao.login("Leon", "1234");
- System.out.println(userDao.getClass().getSuperclass());
- }
- }