JAVA中的代理技术(静态代理和动态代理)
最近看书,有两个地方提到了动态代理,一是在Head First中的代理模式,二是Spring AOP中的AOP。所以有必要补充一下动态代理的相关知识。
Spring采用JDK动态代理和CGLib动态代理的技术在运行期实现AOP。要使用JDK动态代理,目标类必须实现相应的接口,而CGLib不对目标类做任何限制,它通过动态生成目标子类的方式提供代理。JDK在创建代理对象时性能高于CGLib,而生成的代理对象的性能却比CGLib低,如果是singleton的代理,推荐使用CGLib动态代理。-----《Spring3.0就是这么简单p73》
Java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地创建一个代理类,实现一个或者多个接口,并将方法的调用转发到你所指定的类。-----《Head First设计模式p474》
在设计模式中,代理的目的有很多种,包括将请求转发到远端主题、给创建开销大的对象对象提供代表等等;在Spring AOP中提到代理类,基本上是指在普通业务类的基础上实现日志、性能统计、事务的增强。下面所描述的内容也以Spring AOP为基础。
一、静态代理
静态代理是指在编译的时候就生成代理类,因此也成为编译时增强。
实现静态代理常用的方法是通过AspectJ,AspectJ 是一个基于 Java 语言的 AOP 框架,提供了强大的 AOP 功能,主要包含两个部分,第一个部分定义了如何表达、定义 AOP 编程中的语法规范;另一个部分是工具部分,包括编译器、调试工具等。
使用AspectJ的流程是先定义业务类,然后用AspectJ提供的工具生成代理类,在此不详细介绍,如要详细了解,请参考下面的文档链接。
二、动态代理
无需使用任何特殊命令对 Java 源代码进行编译,它采用运行时动态地、在内存中临时生成“代理类”的方式来生成代理。有以下两种使用使用动态代理的方式:
(1)CGLib动态代理
CGLIB(Code Generation Library),简单来说,就是一个高效的代码生成类库,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。在Spring AOP中,它在运行期间生成的代理对象是针对目标类扩展的子类。
(2)JDK动态代理
Spring AOP中建议使用JDK动态代理。此时其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。
Spring到底选择那种代理模式?如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理,所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB代理。上说的是默认情况下,也可以手动配置一些选项使Spring采用CGLIB代理。
org.springframework.transaction.interceptor.TransactionProxyFactoryBean是org.springframework.aop.framework. ProxyConfig的子类,所以可以参照ProxyConfig里的一些设置,将optimize和proxyTargetClass任意一个设置为true都可以强制Spring采用CGLIB代理。
下面重点介绍一下Java的动态代理技术:
java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy) // 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) // 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象,第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
Object invoke(Object proxy, Method method, Object[] args)
实现一个动态添加前后日志的全部逻辑:
package newjava;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//普通对象和代理对象都要实现的接口
interface PersonInterface
{
void meeting();
}
//普通对象
class Person implements PersonInterface
{
@Override
public void meeting() {
System.out.println("meeting...");
}
}
//代理处理器
class PersonHander implements InvocationHandler
{
Person person;
PersonHander(Person p)
{
person = p;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//进行前后织入
if (method.getName().equals("meeting"))
{
System.out.println("good morning before metting");
Object obj = method.invoke(person, args); //调用原始类的meeting方法
System.out.println("good afternoon after metting");
return obj;
}
return null;
} }
//测试类
public class ProxyTest {
public static void main(String[] args)
{
//普通对象
Person p = new Person();
//创建代理对象,必须转换为实现的接口
PersonInterface personProxy = (PersonInterface) Proxy.newProxyInstance(
p.getClass().getClassLoader(),
p.getClass().getInterfaces(),
new PersonHander(p)
);
//调用被代理后的方法,其实就是invoke方法,参数:代理对象本身,meeting对应的Method对象、实际参数都会传递到invoke里面去
personProxy.meeting();
}
}
参考:
http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/
http://www.cnblogs.com/phoebus0501/archive/2011/03/11/1980569.html
http://www.flyne.org/article/255
JAVA中的代理技术(静态代理和动态代理)的更多相关文章
- 动态代理的两种方式,以及区别(静态代理、JDK与CGLIB动态代理、AOP+IoC)
Spring学习总结(二)——静态代理.JDK与CGLIB动态代理.AOP+IoC 目录 一.为什么需要代理模式 二.静态代理 三.动态代理,使用JDK内置的Proxy实现 四.动态代理,使用cg ...
- 代理模式(静态代理、JDK动态代理原理分析、CGLIB动态代理)
代理模式 代理模式是设计模式之一,为一个对象提供一个替身或者占位符以控制对这个对象的访问,它给目标对象提供一个代理对象,由代理对象控制对目标对象的访问. 那么为什么要使用代理模式呢? 1.隔离,客户端 ...
- 第89节:Java中的反射技术
第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...
- Java动态代理:一个面包店的动态代理帝国
文章首发于[博客园-陈树义],点击跳转到原文大白话说Java动态代理:一个面包店的动态代理帝国 代理模式是设计模式中非常重要的一种类型,而设计模式又是编程中非常重要的知识点,特别是在业务系统的重构中, ...
- Java动态代理(三)——Cglib动态代理
一.Cglib动态代理Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用Cglib即使代理类没有实现任何接口也可以实现动态代理功能.而且,它的运行速度要远远快 ...
- Java中的多线程技术全面详解
本文主要从整体上介绍Java中的多线程技术,对于一些重要的基础概念会进行相对详细的介绍,若有叙述不清晰或是不正确的地方,希望大家指出,谢谢大家:) 为什么使用多线程 并发与并行 我们知道,在单核机器上 ...
- Spring 的AOP底层实现技术:JDK和CGLIB动态代理
Spring 的AOP实现技术之JDK的动态代理技术实例: 接口:IUserService (Spring的AOP是动态AOP,实现技术:JDK提供的动态代理和cglib代理,cglib它可以为没有实 ...
- Java 中不允许使用静态局部变量
Java 中不允许使用静态局部变量
- 代理模式(Proxy)--动态代理(JDK)
在是上一篇博客中实现了静态代理. 在上篇的结尾提到了一个问题: 思考:如果我们下需要对火车,自行车实现相同的代理,我们又该如何实现呢? 这篇博客就来解决这个问题: 解决这类问题需要用到动态代理技术,实 ...
- 性能优于JDK代理,CGLib如何实现动态代理
按照代理的创建时期,代理类可以分为两种. 静态代理:由程序员创建或特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. 动态代理:在程序运行时,运用反射机制动态创建 ...
随机推荐
- MySQL锁系列2 表锁
http://www.cnblogs.com/xpchild/p/3789068.html 上一篇介绍了MySQL源码中保护内存结构或变量的锁,这里开始介绍下MySQL事务中的表锁. 注1: 在表 ...
- VBA Excel 常用 自定义函数
1. 将 互换 Excel 列号(数字/字母) Public Function excelColumn_numLetter_interchange(numOrLetter) As String Dim ...
- java_有返回值线程_提前加载例子
package com.demo.test3; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionE ...
- python中文处理之encode/decode函数
python中文处理相信迷惑过不少同学.下面说说python2/3的encode和decode函数. python2中,使用decode()和encode()来进行解码和编码,以unicode类型作为 ...
- B. Painting Pebbles
B. Painting Pebbles time limit per test 1 second memory limit per test 256 megabytes input standard ...
- struts2.1笔记03:AOP编程和拦截器概念的简介
1.AOP编程 AOP编程,也叫面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容.利用A ...
- mongoDB操作命令及mongoDB的helper
此项目已开源,开源地址是: http://mongodbhelper-csharp.googlecode.com/svn/trunk/ mongodb的helper using System; usi ...
- 实现Square类,让其继承自Rectangle类,并在Square类增添新属性和方法,在2的基础上,在Square类中重写Rectangle类中的初始化和打印方法
实现Square类,让其继承自Rectangle类,并在Square类增添新属性和方法,在2的基础上,在Square类中重写Rectangle类中的初始化和打印方法 #import <Found ...
- 3.4.2内核下的I2C驱动
1. 框架1.1 硬件协议简介1.2 驱动框架1.3 bus-drv-dev模型及写程序a. 设备的4种构建方法a.1 定义一个i2c_board_info, 里面有:名字, 设备地址 然后i2c_r ...
- CF Exam (数学)
Exam time limit per test 1 second memory limit per test 256 megabytes input standard input output s ...