java动态代理(1)
来源:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html#
java动态代理(JDK和cglib)
JAVA的动态代理
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
首先看一下静态代理:
1、Count.java
- package net.battier.dao;
- /**
- * 定义一个账户接口
- *
- * @author Administrator
- *
- */
- public interface Count {
- // 查看账户方法
- public void queryCount();
- // 修改账户方法
- public void updateCount();
- }
2、CountImpl.java
- package net.battier.dao.impl;
- import net.battier.dao.Count;
- /**
- * 委托类(包含业务逻辑)
- *
- * @author Administrator
- *
- */
- public class CountImpl implements Count {
- @Override
- public void queryCount() {
- System.out.println("查看账户方法...");
- }
- @Override
- public void updateCount() {
- System.out.println("修改账户方法...");
- }
- }
- 、CountProxy.java
- package net.battier.dao.impl;
- import net.battier.dao.Count;
- /**
- * 这是一个代理类(增强CountImpl实现类)
- *
- * @author Administrator
- *
- */
- 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("事务处理之后");
- }
- }
3、TestCount.java
- package net.battier.test;
- import net.battier.dao.impl.CountImpl;
- import net.battier.dao.impl.CountProxy;
- /**
- *测试Count类
- *
- * @author Administrator
- *
- */
- public class TestCount {
- public static void main(String[] args) {
- CountImpl countImpl = new CountImpl();
- CountProxy countProxy = new CountProxy(countImpl);
- countProxy.updateCount();
- countProxy.queryCount();
- }
- }
观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
再来看一下动态代理:
JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数
可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理示例:
1、BookFacade.java
- package net.battier.dao;
- public interface BookFacade {
- public void addBook();
- }
2、BookFacadeImpl.java
- package net.battier.dao.impl;
- import net.battier.dao.BookFacade;
- public class BookFacadeImpl implements BookFacade {
- @Override
- public void addBook() {
- System.out.println("增加图书方法。。。");
- }
- }
- 、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;
- }
- }
3、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();
- }
- }
java动态代理(1)的更多相关文章
- 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的动态代理,然后就有了这篇文章 ...
- Java 动态代理
被代理的接口特点: 1. 不能有重复的接口,以避免动态代理类代码生成时的编译错误. 2. 这些接口对于类装载器必须可见,否则类装载器将无法链接它们,将会导致类定义失败. 3. 需被代理的所有非 pub ...
- [转]java动态代理(JDK和cglib)
转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...
- java动态代理模式
java动态代理机制详解 Spring的核心AOP的原理就是java的动态代理机制. 在java的动态代理机制中,有两个重要的类或接口: 1.InvocationHandler(Interface): ...
随机推荐
- White space is required before the encoding pseudo attribute in the XML declaration.
错误出现的位置: <?xml version="1.0"encoding="UTF-8"?> 正确方式: <?xml version=&quo ...
- PostgreSQL 类型转换 -除法
PostgreSQL 类型转换 类似Oracle ,PostgreSQL也有强大的类型转换函数, 下面仅举两个类型转换例子. --1 例子 postgres=# select 1/4; ?colum ...
- cobaltstrike3.5使用记录
一.服务器搭建与连接(1)团队服务器上: sudo ./teamserver 服务器IP 连接密码 (VPS的话要写外网ip,并且可以进行端口映射,默认使用50050端口) 但是这个一关闭团队服务器也 ...
- $_SERVER 等超全局数组的用法 $_COOKIE $_GET $_SESSION
$_SERVER 服务器和执行环境信息 例如 $_SERVER['SERVER_NAME']; 当前运行脚本所在的服务器的主机名.如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定.$_G ...
- JavaScript功能规划的基本语法总结
1.迭代数组 1)map 方法会迭代数组中的每一个元素,并根据回调函数来处理每一个元素,最后返回一个新数组.注意,这个方法不会改变原始数组 //例子 var oldArray = [1,2,3,4,5 ...
- hdu_5790_Prefix(trie+主席树)
题目链接:hdu_5790_Prefix 题意: 给你n个字符串,字符串总长度不超过10W,然后给你一个区间,问你这个区间的字符串不相同的前缀有多少个. 题解: 由于z与上一个答案有关,所以强制在线, ...
- [SOJ]1753 解码
1753. 解码 Constraints Time Limit: 1 secs, Memory Limit: 32 MB Description ZX是另一头04级的牛,他现在在UPen.他跟LLK经 ...
- C# 语言规范_版本5.0 (第3章 基本概念)
1. 基本概念 1.1 应用程序启动 具有入口点 (entry point) 的程序集称为应用程序 (application).应用程序运行时,将创建新的应用程序域 (application doma ...
- Visual Studio 2010 安装帮助文档问题
今天重装系统,装完VS2010后,如往常一样安装文档,却弹出如下错误"Could not create the local store in the specified folder.... ...
- 关于 JAVA 中使用 Preferences 读写注册表时要注意的地方
要注意的只有一个地方,那就是键名或者项名不要包含大写字母,否则读不到数据. 代码是这样的: 1: Preferences preferences = Preferences.systemRoot(); ...