2017.5.1 java动态代理总结
参考来自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
1.代理模式
代理类和委托类有相同接口。
代理类负责为委托类:预处理消息
过滤消息
把消息转发给委托类
事后处理消息等
代理类和委托类会相关联。
代理类不真正实现服务,而是通过调用委托类的相关方法,来提供服务。
2.代理的分类
静态代理:由程序员创建,或者由特定工具自动生成源代码,再对其编译。在运行之前,代理类的.class文件就存在了。
动态代理:在程序运行时,根据java的反射机制动态创建。
3 jdk动态代理:委托类必须实现接口。
4 Cglib动态代理:委托类不用实现接口,针对类。
2.1 静态代理
(1)实例
public interface Count {
// 查看账户方法
public void queryCount();
// 修改账户方法
public void updateCount();
}
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户方法...");
}
@Override
public void updateCount() {
System.out.println("修改账户方法...");
}
}
创建一个代理类,可以看到CountProxy和CountImpl实现了同样的接口:Count。
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("事务处理之后");
}
}
(2)测试
由测试可知,采用constructor关联起来的proxy和impl,必须是1对1的,十分低效。
public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
显然,通过上面的代码可以知道,这样的代理类只能为一个接口服务,会产生过多的代理类。而且所有的代理类中除了调用的方法不一样,其他操作都一样,重复代码过多。为了使用一个代理类来完成全部的代理功能,显然不能在运行前就生成好代理类的.class文件。即,必须使用动态代理。
2.2 JDK动态代理
(1)interface InvocationHandler
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
(2)class Proxy
java.lang.reflect.Proxy类提供了一个方法:newProxyInstance。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数说明:
1 ClassLoader loader:类加载器
2 Class<?>[] interfaces:得到全部的接口
3 InvocationHandler h:得到InvocationHandler接口的子类实例
(3)实例
1 public interface BookFacade {
2 public void addBook();
3 }
4
5 public class BookFacadeImpl implements BookFacade {
6
7 @Override
8 public void addBook() {
9 System.out.println("增加图书方法。。。");
10 }
11 }
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class BookFacadeProxy implements InvocationHandler {
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target 委托对象
* @return 代理类
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象 //要绑定接口(这是一个缺陷,cglib弥补了)
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
16 target.getClass().getInterfaces(),
17 this);
} @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)测试
由测试可知,此时只需要一个代理类,就可以通用了。但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
public class TestProxy {
public static void main(String[] args) {
BookFacadeProxy proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}
}
2.3 Cglib动态代理
由前面可知,当委托类并没有实现某个接口(implements someInterface)时,jdk动态代理就不能使用了。
cglib是针对类来实现代理(没有实现某个接口也不会造成影响),原理:对委托类生成一个子类(局限:final),并覆盖其中方法实现增强。
(1)实例
public class BookFacadeImpl1 { //没有implements BookFacade
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}
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 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;
}
}
(2)测试
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}
3.总结
静态代理缺点:代码一对一,重复冗余,编译时就需要存在代理类的.class文件。
动态代理优点:动态生成,统一处理,运行时生成代理类。
jdk动态代理: Proxy,InvocationHandler
cglib动态代理:MethodInterceptor
2017.5.1 java动态代理总结的更多相关文章
- java动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- java动态代理实现与原理详细分析(转)
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- Java 动态代理机制详解
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- Java动态代理全面分析
代理模式 解说:给某一个对象提供一个代理,并由代理对象控制对原对象的引用: 代理模式需要以下几个角色: 1 主题:规定代理类和真实对象共同对外暴露的接口: 2 代理类:专门代理真实对象的类: 3 ...
- JAVA动态代理模式(从现实生活角度理解代码原理)
所谓动态代理,即通过代理类:Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联. java动态代理主要是使用java.lang.reflect包中的两个 ...
- Java 动态代理作用是什么?
Java 动态代理作用是什么? 1 条评论 分享 默认排序按时间排序 19 个回答 133赞同反对,不会显示你的姓名 Intopass 程序员,近期沉迷于动漫ING 133 人赞同 ① 首先你 ...
- java动态代理原理
我们经常会用到Java的动态代理技术, 虽然会使用, 但是自己对其中的原理却不是很了解.比如代理对象是如何产生的, InvocationHandler的invoke方法是如何调用的?今天就来深究下Ja ...
- java 动态代理示例,带主要注释
Java proxy是基于反射,仅仅支持基于接口的动态代理. java 动态代理是一切架构的基础,必须了解. 废话少说,先上代码获得感性认识. 示例代码有主要注释. 接口: public interf ...
- java动态代理浅析
最近在公司看到了mybatis与spring整合中MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 于是想起了java的动态代理,然后就有了这篇文章 ...
随机推荐
- Codeforces 938.B Run For Your Prize
B. Run For Your Prize time limit per test 1 second memory limit per test 256 megabytes input standar ...
- [04]JS获取文件大小方法
</pre><pre name="code" class="html"><input id="file" ty ...
- SqliteDeveloper 破解
方法1: 注册表删除 HKEY_CURRENT_USER\SharpPlus\SqliteDev 下的 StartDate 方法2: 安装完成SQLite Developer后,先不要打开软件,下面 ...
- Xcode5 上64位编译 出错No architectures to compile for
http://blog.csdn.net/chocolateloveme/article/details/16900999 详细错误信息如下: No architectures to compile ...
- iOS开发者证书申请及应用上线发布详解
一个小教程登录开发者中心:http://developer.apple.com/ 第零部分:本地生成密钥1.打开mac的钥匙串访问 2.选择钥匙串的证书助理(有些可能是英文的) 3.点击继续后存 ...
- 用css控制table td内文字超出隐藏
(如有错敬请指点,以下是我工作中遇到并且解决的问题) 效果图: 重点是把table设置为table-layout: fixed; 超出的文字隐藏的效果才有. p标签超出的文字隐藏的效果不需要设置这个内 ...
- centos6.5 以 zero-dependency Erlang from RabbitMQ 搭建环境
rabbitmq 官方安装文档可参考:http://www.rabbitmq.com/install-rpm.html ,由于rabbitmq 使用Erlang 开发的,运行环境需要用到Erlang ...
- python的递归算法学习(1)
递归函数在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数.举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以 ...
- hdu 5146(水题)
Sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- (1) SpringBoot创建发布
一.安装jdk8 https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 二.配置环境 ...