java代理(静态代理和jdk动态代理以及cglib代理)

说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等。

记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读过24种设计模式,以及阅读过spring源代码的我竟然答错了,回想起来,真是日了狗了,学过那么多遍的东西都忘记了,结果是装逼失败,自己要狠下心来,把代理都搞懂!


代理模式简述

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 


静态代理

由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。下面通过例子展示。

定义接口

	/** 
	 * 定义一个账户接口 
	 *  
	 * @author Fighter
	 * @date 2016-04-20
	 *  
	 */  
	public interface Count {  
	    // 查看账户方法  
	    public void queryCount();  
	  
	    // 修改账户方法  
	    public void updateCount();  
	  
	} 

实现接口

	/** 
	 * 委托类(包含业务逻辑) 
	 *  
	 * @author Fighter
	 * @date 2016-04-20
	 *  
	 */  
	public class CountImpl implements Count {  
	  
	    @Override  
	    public void queryCount() {  
	        System.out.println("查看账户方法...");  
	  
	    }  
	  
	    @Override  
	    public void updateCount() {  
	        System.out.println("修改账户方法...");  
	  
	    }  
	  
	}  	

添加代理

	/** 
	 * 这是一个代理类(增强CountImpl实现类) 
	 *  
	 * @author Fighter
	 * @date 2016-04-20
	 *  
	 */  
	public class CountProxy implements Count {  
	    private CountImpl countImpl;  
	  
	    /** 
	     * 覆盖默认构造器 
	     *  
	     * @param countImpl 
	     */  
	    public CountProxy(CountImpl countImpl) {  
	        this.countImpl = countImpl;  
	    }  
	  
	    @Override  
	    public void queryCount() {  
	        System.out.println("事务处理之前");  
	        // 调用委托类的方法;  
	        countImpl.queryCount();  
	        System.out.println("事务处理之后");  
	    }  
	  
	    @Override  
	    public void updateCount() {  
	        System.out.println("事务处理之前");  
	        // 调用委托类的方法;  
	        countImpl.updateCount();  
	        System.out.println("事务处理之后");  
	  
	    }  
	  
	}  	

测试

	/** 
	 *测试Count类 
	 *  
	 * @author Fighter
	 * @date 2016-04-20
	 *  
	 */  
	public class TestCount {  
	    public static void main(String[] args) {  
	        CountImpl countImpl = new CountImpl();  
	        CountProxy countProxy = new CountProxy(countImpl);  
	        countProxy.updateCount();  
	        countProxy.queryCount();  
	  
	    }  
	}  	

JDK动态代理

特点:只能对实现了接口的类生产代理,不能针对类


定义接口

	/**
	 * 创建业务接口,包含业务可以提供对外的接口
	 * 
	 * @author Fighter
	 * @date 2016-04-19
	 *
	 */
	public interface UserService{
		
		/**
		 * 目标方法 
		 */
		public void add();
	}

定义实现类

	/**
	 * 创建业务接口实现类
	 * 
	 * @author Fighter
	 * @date 2016-04-19
	 *
	 */
	public class UserServiceImpl implements UserService{
		@Override
		public void add() {
		 System.out.println("----------add----------");
			
		}
	}

定义代理

	/**
	 * 自定义简单的Invocation,对接口提供的方法进行增强
	 * 
	 * @author Fighter
	 * @date 2016-04-19
	 */
	public class MyInvocationHandler implements InvocationHandler {
		
		
		//目标对象
		private Object target;
		
		/**
		 * 构造方法
		 * @param target 目标对象
		 */
		public MyInvocationHandler(Object target) {
			super();
			this.target=target;
		}
		 
	    <span style="white-space:pre">	</span>/**
		 * 执行目标对象的方法 
		 */
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			
			 //在目标方法执行前简单打印一下
			 System.out.println("----------before----------");
			 
			 //执行目标方法对象
			 Object result=method.invoke(target, args);
			 
			 //在目标方法执行之后简单打印一下
			 System.out.println("----------after----------");
			
			 return result;
		}
		
		
		/**
		 * 获取目标对象的代理对象
		 * @return 代理对象
		 */
		public Object getProxy(){
			return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
					this.target.getClass().getInterfaces(),this);
		}
		
		
	}

jdk动态代理测试

	public class ProxyTest{
		
		@Test
		public void testProxy() throws Throwable{
			//实例化目标对象
			UserService userService=new UserServiceImpl();
			
			//实例化Invocation
			MyInvocationHandler invocationHandler=new MyInvocationHandler(userService);
			
			//根据目标生成代理对象
			UserService proxy=(UserService)invocationHandler.getProxy();
			
			//调用代理对象方法
			proxy.add();
		}
	}


CGLIB动态代理示例


JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

CGLIB是一个强大的高性能的代码生成包。被广泛的许多AOP框架使用,如Spring的AOP和dynaop,为他们提供方法的interceptor(拦截),最流行的是OR Mapping工具Hibernate也是使用CGLIB来代理单端的single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现)。EsayMock和jMock是通过模仿(moke)对象来测试java代码的包。他们都是通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。

我们先通过demo来快速了解CGLIB的使用示例。


定义实现类

/** 
 * 这个是没有实现接口的实现类 
 *  
 * @author student 
 *  
 */  
public class BookFacadeImpl {  
    public void addBook() {  
        System.out.println("增加图书的普通方法...");  
    }  
} 

定义代理

/** 
 * 使用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;  
  
  
    }  
  
}  

编写Cglib测试

public class TestCglib {  
      
    public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl bookCglib=(BookFacadeImpl)cglib.getInstance(new BookFacadeImpl());  
        bookCglib.addBook();  
    }  
}  

总结

当阅读到spring的AOP章节的时候发现其中使用了代理的一些方法,在此复习一下代理的一些实现以及操作。代理-Spring AOP的核心设计模式。









你可能感兴趣的:(java)