1. Enhancer和MethodInterceptor
Enhancer可以用来动态的生成一个类,这个类可以继承指定的一个类,实现指定的一些接口。
同时,Enhancer在生成一个类之前需要指定一个Callback,当类方法调用时,方法的执行被分配给这个Callback
MethodInterceptor是一个使用比较多的继承自Callback的接口,它只有一个方法声明
public interface MethodInterceptor
extends Callback
{
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
我们看一下 JDK自带的Invocationhandler接口中的方法声明
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
从参数构成上,methodInterceptor的输入参数比Invocationhandler多1个,其实前3个参数对象的含义与Invocationhandler的含义是相同的
第一个参数表示调用方法来自哪个对象;
第二个参数表示调用方法的Method对象;
第三个参数表示此次调用的输入参数列表;
多出来的参数是MethodProxy 类型的,它应该是cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升
代码示例:
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 MyMethodInterceptor implements MethodInterceptor {
// 接口1
static interface Inter1{
public void fun1();
}
// 接口2
static interface Inter2{
public String fun2(String arg0);
}
// 内部方法
public String myFun1(String arg0){
return "hello," + arg0 ;
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
if( "fun1" .equals(methodName) ){
System. out .println( "[intercept] fun1 invoked" );
return null;
} else if ( "fun2" .equals(methodName) ){
System. out .println( "[intercept] fun2 invoked before" );
String result = (String)args[0] + "..." ;
System. out .println( result );
System. out .println( "[intercept] fun2 invoked after" );
return result;
} else if ( "myFun1" .equals(methodName) ){
System. out .println( "[intercept] myFun1 invoked before" );
Object result = proxy. invokeSuper(obj, args);
System. out .println( result );
System. out .println( "[intercept] myFun1 invoked after" );
return result;
}
return null;
}
public Object createProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyMethodInterceptor. class );
enhancer.setInterfaces( new Class[]{Inter1. class,Inter2. class});
enhancer.setCallback( this );
return enhancer.create();
}
public static void main(String[] args) {
MyMethodInterceptor ss = new MyMethodInterceptor();
Object proxy = ss.createProxy();
// 接口
Inter1 inter1 = (Inter1)proxy;
inter1.fun1();
Inter2 inter2 = (Inter2)proxy;
inter2.fun2( "code generate library" );
// 类
MyMethodInterceptor c1 = (MyMethodInterceptor)proxy;
c1.myFun1( "cglib" );
}
}
执行结果:
[intercept] fun1 invoked
[intercept] fun2 invoked before
code generate library...
[intercept] fun2 invoked after
[intercept] myFun1 invoked before
hello,cglib
[intercept] myFun1 invoked after
我们看到,在intercept()方法中,对调用函数名进行了判断,并进行了不同处理。可以再方法执行之前、之后做一些我们想做的事情,甚至是修改输入参数、输出参数。
MethodProxy在对执行函数的时候,提供了2个方法
public Object invoke (Object obj, Object[] args) throws Throwable
public Object invokeSuper(Object obj, Object[] args) throws Throwable
我们看到,在例子中使用的是invokeSuper()方法,因为动态生成的类是子类或者是实现类,因此invokeSuper就是执行父类中方法的意思。
那么invoke()方法是做什么的。javadoc上说这个方法可以用于 相同类中的其他对象的方法执行,也就是说这个方法中的obj需要传入相同一个类的另一个对象,否则会进入无限递归循环。
通过这个简单的例子,我们可以看到cglib可以动态的生成一个代理,而且这种方法比JDK的动态代理更强大,因为JDK的动态代理,需要代理的类实现某个接口,而cglib没有这个要求,因为它可以直接生成指定类的子类,同时支持实现接口的方式。cglib提供的MethodProxy的执行效率高于JDK自带的反射。
2. CallbackFilter
一个Enhancer生成类可以指定多个Callback,这样对于每次调用有哪个Callback,就需要指定一个CallbackFilter的策略
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CallbackTest {
public void fun1(){
System. out .println( "fun1 invoekd" );
}
public void fun2(){
System. out .println( "fun2 invoekd" );
}
static class ClassA implements MethodInterceptor{
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System. out .println( "ClassA intercept invoked..." );
return proxy.invokeSuper(obj, args);
}
}
static class ClassB implements MethodInterceptor{
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System. out .println( "ClassB intercept invoked..." );
return proxy.invokeSuper(obj, args);
}
}
public Object createProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(getClass());
enhancer.setCallbacks( new Callback[]{ new ClassA(), new ClassB() });
enhancer.setCallbackFilter( new CallbackFilter() {
public int accept(Method method) {
String methodName = method.getName();
if( "fun1" .equals(methodName) ){
return 0;
} else {
return 1;
}
}
});
return enhancer.create();
}
public static void main(String[] args) {
CallbackTest test = new CallbackTest();
CallbackTest obj = (CallbackTest)test.createProxy();
obj.fun1();
obj.fun2();
}
}
输出结果:
ClassA intercept invoked...
fun1 invoekd
ClassB intercept invoked...
fun2 invoekd
我们可以看到,CallbackFilter类的accept()方法的返回值是int类型的,它用来指示此次指派的Callback的次序,从0开始,注意这个返回值必须小于当前指定的Callback的总个数。
3. Mixin
Mixin可以对多个对象进行代理,需要同时指定多个接口和者多个接口对应的代理对象
import net.sf.cglib.proxy.Mixin;
public class MixinTest {
static interface Inter1 {
void fun1(String arg0);
}
static interface Inter2 {
void fun1(String arg0);
void fun2(int arg0);
}
public static void main(String[] args) {
Mixin mixin = Mixin. create( new Class[]{Inter1. class ,Inter2.class },
new Object[]{
new Inter1() {
public void fun1(String arg0) {
System.out .println("Inter1 - " + arg0);
}
},
new Inter2() {
public void fun1(String arg0) {
System.out .println("Inter1 - " + arg0);
}
public void fun2( int arg0) {
System.out .println("Inter2 - " + arg0);
}
}
});
Inter1 inter1 = (Inter1) mixin;
inter1.fun1( "hello" );
Inter2 inter2 = (Inter2) mixin;
inter2.fun1( "world" );
inter2.fun2(999);
}
}
输出结果:
Inter1 - hello
Inter1 - world
Inter2 - 999
我们查看一下classpath下编译之后的class文件
其中,Mixintest$inter1.class和Mixintest$inter2.class是2个内部接口
生成的2个类是MixinTest$1.class和MixinTest$2.class,也就是说其实CGLIB没有为这2个代理对象生成1个类,而是生成了2个类
反编译一下这2个类,我们可以看到生成的Mixin对象其实是引用了这两个类对象
class MixinTest$1
implements MixinTest.Inter1
{
public void fun1(String arg0)
{
System.out.println("Inter1 - " + arg0);
}
}
class MixinTest$2
implements MixinTest.Inter2
{
public void fun1(String arg0)
{
System.out.println("Inter1 - " + arg0);
}
public void fun2(int arg0) {
System.out.println("Inter2 - " + arg0);
}
}
4. BeanCopier
BeanCopier可以实现Bean之间的属性同名属性拷贝
import java.util.Arrays;
import java.util.List;
import net.sf.cglib.beans.BeanCopier;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
public class BeanCopierTest {
static class ClassA{
private String username ;
private String password ;
private String score ;
private List<String> list ;
public String getUsername() {
return username ;
}
public void setUsername(String username) {
this .username = username;
}
public String getPassword() {
return password ;
}
public void setPassword(String password) {
this .password = password;
}
public String getScore() {
return score ;
}
public void setScore(String score) {
this .score = score;
}
public List<String> getList() {
return list ;
}
public void setList(List<String> list) {
this .list = list;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString( this , ToStringStyle.MULTI_LINE_STYLE );
}
}
static class ClassB{
private String username ;
private String password ;
private String address ;
private List<Integer> list ;
public String getUsername() {
return username ;
}
public void setUsername(String username) {
this .username = username;
}
public String getPassword() {
return password ;
}
public void setPassword(String password) {
this .password = password;
}
public String getAddress() {
return address ;
}
public void setAddress(String address) {
this .address = address;
}
public List<Integer> getList() {
return list ;
}
public void setList(List<Integer> list) {
this .list = list;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString( this , ToStringStyle.MULTI_LINE_STYLE );
}
}
public static void main(String[] args) {
BeanCopier beanCopier = BeanCopier.create(ClassA. class,ClassB. class ,false );
List<String> list = Arrays. asList( new String[]{ "a" ,"b" ,"c" } );
ClassA a = new ClassA();
a.setUsername( "hello" );
a.setPassword( "world" );
a.setScore( "99" );
a.setList(list);
ClassB b = new ClassB();
b.setUsername( "hello" );
b.setPassword( "world" );
b.setAddress( "beijing" );
beanCopier.copy(a, b, null );
System. out .println( a );
System. out .println( b );
}
}
我们可以看到,对于2个对象中的同名属性 username 和 password进行了拷贝,并且对内部的符合属性List a 也进行了复制,但是,通过debug我们可以发现,内部的符合属性其实并没有实现copy
因为他们在内存中实现上是同一个对象,对于内置复合对象的拷贝,需要寻找其他途径。而且,虽然ClassA中是List<String>,ClassB中是List<Integer>,在赋值的时候并没有抛出异常,也就是仅仅是内存上的赋值成功,并没有进行繁星检查,这也充分说明Java的泛型为伪泛型,在运行时会“泛型”会消失。但是如果此后在调用赋值之后的泛型不支持的方法时,就可能会遇到运行时异常。这会是一个安全隐患。
- 大小: 2.3 KB
- 大小: 24.1 KB
分享到:
相关推荐
在本篇Spring学习笔记中,我们将探讨如何使用CGLIB库来实现AOP功能。 CGLIB(Code Generation Library)是一个强大的高性能的代码生成库,它被广泛用于动态代理和运行时织入AOP切面。在Spring中,如果目标类没有...
本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...
### hibernate框架学习笔记整理 #### 一、Hibernate框架简介 **Hibernate框架**是一种用于Java应用的**对象关系映射**(Object-Relational Mapping, ORM)解决方案,它允许开发者使用面向对象的方式操作数据库中的表...
《Spring技术内幕 学习笔记》是一份深入探讨Spring框架核心机制的学习资料,结合作者zzc1684在iteye博客上的博文,我们可以从中学习到Spring框架的多个重要知识点。Spring作为Java企业级应用开发的基石,其设计思想...
### Spring编程学习笔记知识点概述 #### 一、Spring框架简介 Spring框架是一个开源的轻量级Java开发框架,主要用于简化企业级应用的开发工作。它提供了全面的基础架构支持,包括但不限于依赖注入(Dependency ...
学习笔记涵盖了Hibernate的基础概念、配置、实体类的创建、数据类型映射、关系映射(一对一、一对多、多对多)、查询语言HQL、 Criteria API、CGLIB动态代理等核心内容。笔记详细记录了每个知识点的原理和实践步骤...
【标题】"Spring学习笔记(十四)"主要涵盖了Spring框架中的AOP(面向切面编程)和CGLIB库的应用,这两个知识点在Java开发中尤为重要,尤其是对于构建灵活、可维护的大型企业级应用。 首先,Spring框架是Java开发中...
### JPA 学习笔记详解 #### 一、JPA 概述 Java Persistence API (JPA) 是 Sun 公司提出的一种 Java 持久层标准,它为 Java 开发者提供了一种对象关系映射 (ORM) 的工具来管理 Java 应用程序中的关系型数据。JPA ...
【标题】"Spring学习笔记(十三)"主要涉及的是Spring框架中的AOP(面向切面编程)部分,特别是关于CGLIB动态代理的实现。在Spring中,AOP是一种强大的编程模型,它允许开发者定义“切面”,即关注点的模块化,如日志...
【标题】"Spring学习笔记(八)"主要涵盖了Spring框架中的动态代理机制,这是Spring AOP(面向切面编程)的核心技术之一。动态代理允许我们在不修改原有代码的情况下,为对象添加额外的功能,如日志、事务管理等。在这...
### Spring学习笔记:深入理解AOP与Annotation驱动的动态代理 #### 核心知识点解析: 在探讨Spring框架中AOP(面向切面编程)及基于Annotation的动态代理之前,我们首先需要了解AOP的基本概念及其在Spring中的实现...
在本篇Spring学习笔记中,我们将深入探讨Spring的几个关键知识点,包括其优点、AOP的实现原理以及声明式事务管理。 首先,Spring的优点在于它的轻量级特性,它不对现有类结构造成入侵,允许开发者专注于业务逻辑。...
### Spring2.5 学习笔记详解 #### 一、Spring 框架简介 Spring 是一个开源的轻量级 Java 开发框架,主要用于简化企业级应用的开发工作。Spring 提供了一系列强大的功能,比如控制反转 (Inversion of Control, IOC)...
在本篇"Spring 学习笔记六"中,我们将深入探讨Spring框架的核心概念和技术细节,同时结合源码分析,以提升对Spring的理解和应用能力。本文档主要关注Spring的依赖注入(Dependency Injection,DI)机制、AOP(面向切...
这个"spring学习笔记,包括源码学习"的资料很可能包含了一系列关于Spring框架的核心概念、配置、使用方法以及深入源码的解析。 首先,让我们来了解一下Spring框架的基础知识。Spring的核心特性是依赖注入,它允许...
【Spring 学习笔记四】 在本篇Spring学习笔记中,我们将深入探讨Spring框架的核心特性,包括依赖注入(Dependency Injection,DI)、AOP(面向切面编程)以及Spring的源码解析,同时也会介绍一些实用的开发工具。...
以下将详细介绍Spring学习笔记中的主要知识点。 **面向抽象编程** 面向抽象编程是一种设计原则,强调在代码中使用接口或抽象类,而不是具体实现类。这使得系统更具有灵活性,易于扩展和维护。在Spring框架中,我们...
本学习笔记将深入探讨动态SQL的概念及其在MyBatis中的应用,同时结合相关库如Javassist、CGLIB等进行解析。 首先,动态SQL的核心思想是避免硬编码大量的静态SQL语句,而是通过程序逻辑来动态生成SQL。这提高了代码...
### Spring2.5.6 学习笔记精粹解析 #### 一、Spring框架环境搭建与JAR包配置 在开始深入Spring框架的学习之前,首先需要确保开发环境正确配置Spring框架。按照“传智播客Spring2.5.6学习笔记最新整理”的指引,...