一:在JDK里也有动态代理的类和接口,是Proxy和InvocationHandler,但是Proxy只能为接口产生代理类,借助InvocationHandler的实现类来完成对类对象的代理;

但是在Spring里可以为没有实现接口的类进行aop编程,这时候要模拟则可以借助cglib的Enhancer类和MethodInterceptor接口来实现;

下面的代码实现里有很多即兴的注释,诸君可忽略;

二:pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>me.silentdoer</groupId>
<artifactId>demo-test-something</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--<packaging>war</packaging>-->
<name>Silentdoer</name>
<description>描述</description> <developers>
<developer>
<id>Silentdoer</id>
<name>Mr.Wang</name>
<email>1010993610@qq.com</email>
<roles>
<role>C# Engineer</role>
<role>Java Engineer</role>
</roles>
</developer>
</developers> <dependencies>
<!-- tool begin -->
<dependency>
<groupId>${alibaba.group}</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>${dom4j.group}</groupId>
<artifactId>dom4j</artifactId>
<version>${dom4j.version}</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
<!-- 这个版本的可以不用再添加asm的jar包 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.1</version>
</dependency>
<!-- tool end -->
</dependencies> <build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build> </project>

三:代码实现

1.advice的实现

package me.silentdoer.cglibusage.proxy.method;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map; /**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/22/18 2:35 PM
*/
// 和Spring中的 aopalliance 的 MethodInterceptor 类似,不过aopalliance接口的是invoke方法且参数只有一个MethodInvocation
public class TestAdvice implements MethodInterceptor {
//private Object target; // TODO 如果target是用默认构造方法创建对象后不需要额外操作,那么此属性是可以忽略的;
// 通过添加一个map(可以自己扩展一个更符合tx:advice定义的结构)作为注册表可以实现txAdvice的传播特性
// ,原理是intercept里获得当前方法名然后和map的String匹配看是什么传播特性,然后做相关的操作
private Map<String, Object> attributes;
// Mybatis的实现Mapper接口也是用类似的方式实现的,即这里有个map,里面存储了方法名和对应的statement之间的关联
//,然后执行Mapper接口的方法实际上是执行代理类的invoke方法,invoke方法里获得当前方法的名称然后从map里获得对应的statement
//,最终通过sqlSession.selectOne(statement)完成操作; // o是Enhancer产生的代理类对象,method是被代理类的对应方法对象,objects是方法参数,methodProxy则是特殊的类似method的对象
// 这里之所以需要methodProxy是因为和JDK的Proxy-InvocationHandler不同,Proxy只能为接口产生代理类,而o则是InvocationHandler的属性
//,它是和代理类没有半毛钱直接关系的,执行method.invoke(o...)就是执行被代理类的方法;而Enhancer是能够为类产生代理类同时产生此类的默认构造
//,方法的对象,那么如果被代理类被创建后不需要做其它操作则不应该作为MethodInterceptor对象的属性而浪费对象,那么这时候由于o是代理类对象
//,因此需要一个能够执行o继承的类对象的方法,因此需要methodProxy;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// TODO 可以用cglib实现 aop 编程,这里其实已经是一个aop编程了,关键是通过解析配置,然后转换后的配置存到此对象的注册表里
// TODO 这里则根据method名称和其它一些特性从而在注册表里获取advice并执行before和after方法(它们的默认实现是空实现,因此
// TODO 自己写Advice时没有实现before则此advice就是值有after的
System.out.println("Before"); // bu shi zhi ru, before ye shi dai li shi xian
// output: class me.silentdoer.cglibusage.test.TestContext$$EnhancerByCGLIB$$379b92c3
System.out.println(o.getClass());
// output: class me.silentdoer.cglibusage.test.TestContext
System.out.println(method.getDeclaringClass());
// output: [88] // 参数列表
System.out.println(String.format("Args: %s", Arrays.toString(objects)));
// 这个和Aspectj的JoinPoint很像
// output: test
System.out.println(methodProxy.getSignature().getName());
// 类似aspectj的ProceedingJoinPoint
// 如果用的是invoke方法会产生递归现象,因为执行的是代理类的方法又会间接再执行此intercept方法;
Object result = methodProxy.invokeSuper(o, objects);
// 由于多态性o是继承自method的声明类的,这种方式也一样是执行的是o的方法
//Object result = method.invoke(o, objects);
System.out.println("After");
return result;
} public void setAttributes(Map<String, Object> attributes) {
this.attributes = attributes;
}
}

2.被代理类

package me.silentdoer.cglibusage.test;

/**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/22/18 2:26 PM
*/
public class TestContext {
public String test(long s){
System.out.println(String.format("Hello:%s", s));
return "AAAAAa" + s;
}
}

3.main方法

package me.silentdoer.cglibusage;

import me.silentdoer.cglibusage.proxy.method.TestAdvice;
import me.silentdoer.cglibusage.test.TestContext;
import net.sf.cglib.proxy.Enhancer; /**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/22/18 2:25 PM
*/
public class Entrance {
public static void main(String[] args){
TestContext context = new TestContext();
System.out.println(context.test(88L));
// 如果被代理的TestContext有特殊性则应该改写TestAdvice,改成和InvocationHandler的实现方式引用一个target;
TestContext testContext = ((TestContext) Enhancer.create(TestContext.class, new TestAdvice()));
System.out.println(testContext.test(88L));
}
}

通过这个类是可以实现aop功能的,spring内部也很多地方用到了这个包的api;

用cglib包来为类产生动态代理类对象的更多相关文章

  1. java代理模式及动态代理类

     1.      代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用 ...

  2. CGLIB 和 JDK生成动态代理类的区别(转)

    文章转自http://luyuanliang.iteye.com/blog/1137292 AOP 使用的设计模式就是代理模式,是对IOC设计的补充.为了扩展性,往往会加上反射,动态生成字节码,生成代 ...

  3. spring AbstractBeanDefinition创建bean类型是动态代理类的方式

    1.接口 Class<?> resourceClass 2.获取builder BeanDefinitionBuilder builder = BeanDefinitionBuilder. ...

  4. TZ_05_Spring_Proxy基于接口的动态代理和基于类的动态代理

    代理:为了增强方法在不添加代码的情况下 1.Proxy基于接口的动态代理 /** * 模拟一个消费者 * @author Administrator * */ public class Client ...

  5. Alibaba Java诊断工具Arthas查看Dubbo动态代理类

    原创/朱季谦 阅读Dubbo源码过程中,会发现,Dubbo消费端在做远程调用时,默认通过 Javassist 框架为服务接口生成动态代理类,接着再去调用代理类实现远程接口调用.在阅读这部分源码时,最后 ...

  6. WebServeice 动态代理类

    1, webservice是什么? 是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序 ...

  7. C#使用Emit构造拦截器动态代理类

    在AOP编程概念介绍中,常见的示例为拦截对象,并在对象的某方法执行前和执行后分别记录日志. 而最常用的拦截方式是使用动态代理类,用其封装一个日志拦截器,当方法被执行时进行日志记录. 日志拦截器类 1 ...

  8. .Net基础——程序集与CIL HttpClient封装方法 .Net Core 编码规范 C#中invoke和beginInvoke的使用 WebServeice 动态代理类

    .Net基础——程序集与CIL   1. 程序集和CIL: 程序集是由.NET语言的编译器接受源代码文件产生的输出文件,通常分为 exe和dll两类,其中exe包含Main入口方法可以双击执行,dll ...

  9. 初看Mybatis 源码 (二) Java动态代理类

    先抛出一个问题,用过Mybatis的都知道,我们只需要定义一个Dao的接口,在里面写上一些CRUD相关操作,然后配置一下sql映射文件,就可以达到调用接口中的方法,然后执行sql语句的效果,为什么呢? ...

随机推荐

  1. ScrollView嵌套ListView,禁止ListView的滚动,只让ScrollView可以滚动

    自定义ListView,xml布局文件中使用该自定义的ListView public class NoScrollListview extends ListView{ public NoScrollL ...

  2. sqlite c#

    https://www.cnblogs.com/icebutterfly/p/7850689.html https://www.cnblogs.com/sdadx/p/7127098.html

  3. python 创建一次性,快速的小型web服务

  4. go 语言实现一个简单的 web 服务器

    学习Go语言的一些感受,不一定准确. 假如发生战争,JAVA一般都是充当航母战斗群的角色.一旦出动,就是护卫舰.巡洋舰.航母舰载机.预警机.电子战飞机.潜艇等等浩浩荡荡,杀将过去.(JVM,数十个JA ...

  5. 在linux上创建slave节点

    在slave机器上创建一登录用户,步骤如下: 切换至/usr/sbin目录,执行useradd -m test007  -d /home/test007,test007就是我们所创建的用户 执行su+ ...

  6. js全局作用域

    全局作用域 不在任何函数内定义的变量就具有全局作用域.实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性: var course = 'L ...

  7. 添加exe为windows service服务

    [方法一] 一.介绍 srvany.exe是Microsoft Windows Resource Kits工具集的一个实用小工具,用于将EXE程序作为Windows服务运行.srvany是其注册程序的 ...

  8. VirtualBox安装android-x86-4.4-r2

    https://jingyan.baidu.com/album/a681b0de1373133b184346cf.html?picindex=10

  9. tar 解压某个指定的文件或者文件夹

    1. 先查看压缩文档中有那些文件,如果都不清楚文件内容,然后就直接解压,这个是不可能的 使用#tar -tf 压缩包名称,可以查看压缩包内容 2.解压某个文件 tar -zxvf zabbix.tar ...

  10. C#程序如何以管理员身份运行

    VISTA 和 Windows 7 都使用了UAC来控制程序访问,对于一些需要使用管理员身份运行的程序就得右键以管理员身份运行. C# 编程中可以使程序自动使用管理员身份运行,也就是我们常常看到一些程 ...