java代理(静态代理和jdk动态代理以及cglib代理)
2016-04-20 17:34
781 查看
说到代理,脑袋中浮现一大堆代理相关的名词,代理模式,静态代理,jdk代理,cglib代理等等。
记忆特别深刻的是,一次面试中,一位面试官问我,spring的AOP核心采用的设计模式是什么什么模式,阅读过24种设计模式,以及阅读过spring源代码的我竟然答错了,回想起来,真是日了狗了,学过那么多遍的东西都忘记了,结果是装逼失败,自己要狠下心来,把代理都搞懂!
CGLIB是一个强大的高性能的代码生成包。被广泛的许多AOP框架使用,如Spring的AOP和dynaop,为他们提供方法的interceptor(拦截),最流行的是OR
Mapping工具Hibernate也是使用CGLIB来代理单端的single-ended(多对一和一对一)关联(对集合的延迟抓取是采用其他机制实现)。EsayMock和jMock是通过模仿(moke)对象来测试java代码的包。他们都是通过使用CGLIB来为那些没有接口的类创建模仿(moke)对象。
我们先通过demo来快速了解CGLIB的使用示例。
AOP的核心设计模式。
记忆特别深刻的是,一次面试中,一位面试官问我,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章节的时候发现其中使用了代理的一些方法,在此复习一下代理的一些实现以及操作。代理-SpringAOP的核心设计模式。
相关文章推荐
- JDK容器与并发—Map—HashMap
- JDK容器与并发—Map
- java 中==和equals的区别
- JDK容器与并发—List—CopyOnWriteArrayList
- springMVC自定义注解实现用户行为验证
- Java泛型接口
- JDK容器与并发—List—LinkedList
- JDK容器与并发—List—ArrayList
- spring 启动完成后事件监听器处理
- JDK容器与并发—JDK容器框架
- Java-单机版的书店管理系统(练习设计模块和思想_系列汇总)
- Java-单机版的书店管理系统(练习设计模块和思想_系列汇总)
- java 利用数组实现循环队列
- 【JAVA学习】类的继承
- RxJava介绍和使用
- java汉字转UTF-8编码
- Leetcode - Pascal's Triangle
- spring事务管理的注解和配置
- Java Thread 总结
- 《JAVA与模式》之适配器模式