使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口
定义两个接口
package AOP;
public interface Business1 {
public void show_Business1();
}
package AOP;
public interface Business2 {
public void show_Business2();
}
定义实现类:
package AOP;
public class Business implements Business1, Business2 {
@Override
public void show_Business2() {
System.out.println("show_Business2");
}
@Override
public void show_Business1() {
System.out.println("show_Business1");
}
}
定义日志拦截:
package AOP;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class LogInvocationHandler implements InvocationHandler {
private Object target; // 目标对象
LogInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 执行原有逻辑
Object rev = method.invoke(target, args);
System.out.println(method.getName()+":");
return rev;
}
}
定义动态实现类
package AOP;
import java.lang.reflect.Proxy;
public class DynamicProxyDemo {
/**
* @param args
*/
public static void main(String[] args) {
Class[] proxyInterface = new Class[] { Business1.class, Business2.class };
ClassLoader classLoader = DynamicProxyDemo.class.getClassLoader();
LogInvocationHandler logInvocationHandler = new LogInvocationHandler(
new Business());
Business1 business1=(Business1)Proxy.newProxyInstance(classLoader, proxyInterface,
logInvocationHandler);
business1.show_Business1();
((Business2)business1).show_Business2();
}
}
CglibTest
package Cglib;
import net.sf.cglib.proxy.Enhancer;
public class CglibTest {
public static void main(String[] args) {
byteCodeGe();
}
public static void byteCodeGe() {
// 创建一个织入器
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(Business.class);
// 设置需要织入的逻辑
enhancer.setCallback(new LogIntercept());
// 使用织入器创建子类
Business newBusiness = (Business) enhancer.create();
newBusiness.show_Business1();
newBusiness.show_Business2();
}
}
Intercept
package Cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 记录日志
*/
public class LogIntercept implements MethodInterceptor {
@Override
public Object intercept(Object target, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// 执行原有逻辑,注意这里是invokeSuper
Object rev = proxy.invokeSuper(target, args);
// 执行织入的日志
System.out.println("记录日志");
return rev;
}
}
业务逻辑
package Cglib;
public class Business {
public void show_Business2() {
System.out.println("show_Business2");
}
public void show_Business1() {
System.out.println("show_Business1");
}
}
3.3 自定义类加载器
如果我们实现了一个自定义类加载器,在类加载到JVM之前直接修改某些类的方法,并将切入逻辑织入到这个方法里,然后将修改后的字节码文件交给虚拟机运行,那岂不是更直接。
Javassist是一个编辑字节码的框架,可以让你很简单地操作字节码。它可以在运行期定义或修改Class。使用Javassist实现AOP的原理是在字节码加载前直接修改需要切入的方法。这比使用Cglib实现AOP更加高效,并且没太多限制,实现原理如下图:
public static void main(String[] args) throws Throwable {
//获取存放CtClass的容器ClassPool
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get(className);
// CtMethod targetM = null;
CtMethod targetM = cc.getDeclaredMethod("doSomeThing");
targetM.insertBefore("{ System.out.println(\"记录日志前\"); }");
targetM.insertAfter("{ System.out.println(\"记录日志后\"); }");
Class c = cc.toClass();
Business b = (Business) c.newInstance();
b.doSomeThing2();
b.doSomeThing();
}
Business
public class Business {
public boolean doSomeThing() {
System.out.println("doSomeThing");
return true;
}
public void doSomeThing2() {
System.out.println("doSomeThing2");
}
}
3.4 字节码转换
自定义的类加载器实现AOP只能拦截自己加载的字节码,那么有没有一种方式能够监控所有类加载器加载字节码呢?有,使用Instrumentation,它是 Java 5 提供的新特性,使用 Instrumentation,开发者可以构建一个字节码转换器,在字节码加载前进行转换。本节使用Instrumentation和javassist来实现AOP。
3.4.1 构建字节码转换器
首先需要创建字节码转换器,该转换器负责拦截Business类,并在Business类的doSomeThing方法前使用javassist加入记录日志的代码。
4 AOP实战
说了这么多理论,那AOP到底能做什么呢? AOP能做的事情非常多。
性能监控,在方法调用前后记录调用时间,方法执行太长或超时报警。
缓存代理,缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
软件破解,使用AOP修改软件的验证类的判断逻辑。
记录日志,在方法执行前后记录系统日志。
工作流系统,工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务。
权限验证,方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。
分享到:
相关推荐
java jdk 动态代理 演示demo
java jdk 动态代理演示demo2 包含将生成的字节码保存到本地
java jdk 动态代理演示demo
为了说明Spring的AOP原理,本人使用代理模式中的动态代理完成演示AOP编程的原理的演示。相信,如果你耐心看完整个程序(几乎一行注释一行代码),那么你对Spring这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...
动态代理一个简单实用的JDK动态代理演示
这是使用cglib演示动态代理是需要用到的jar包
演示了Java动态代理技术,学习查看详细的实现细节,更多代码的说明请参考博客文章 :http://520code.net/index.php/archives/19/
Java动态代理和Java反射的Demo演示,通俗易懂。
JAVA JDK静态代理、动态代理、CGlib代理的代码演示 为对象增加功能
单例设计模式案例演示 单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,**应用该模式的这个类只有一个实例**。即一个类只有一个对象实例。 #### 单例设计模式实现步骤 ...动态代理案例演示
Hibernate 的 二级缓存 学习案例 案例代码 接下来,就通过一个案例来演示Spring中JDK动态代理的实现过程,具体代码请参见教材3.2.1小节。 CGLIB代理 通过前面的学习可知,JDK的动态代理用起来非常简单,但它是有...
[Spring]基于Spring框架的Web应用演示(附带cglib工具进行动态代理)
本压缩文件包含两个项目,用于演示如何输出JDK和CGLib动态代理产生的class文件,欢迎下载!
Java Jdk 和 Cglib 动态代理 Demo 1.通过 JDK 反射形式创建动态代理 2.通过CGLIB基于ASM字节码技术创建动态代理 3.Java 反射原理演示 4.CGLib 依赖如下: <groupId>cglib <artifactId>cglib <version>3.3.0 ...
使用java完成动态代理的演示代码,适合初学者理解动态代理的功能,进行参考,本代码是简单的demo代码,仅用于学习参考。
NULL 博文链接:https://coolszy.iteye.com/blog/523111
我们还提供了实际示例,演示如何在Spring AOP中使用JDK动态代理。 CGLib动态代理: 我们将深入研究CGLib动态代理,它允许您在不需要接口的情况下创建代理对象。您将了解CGLib的工作原理,以及如何生成子类来实现...
静态代理是通过手动编写代理类来实现代理的,而动态代理则是通过使用代理工厂或代理类生成器来生成代理对象。 二、静态代理 静态代理是通过手动编写代理类来实现代理的。例如,我们可以创建一个MathProxy类,它...
分析Java代理模式的使用方式,和JDK内部动态代理的实现机制,演示如何自己去实现一个动态代理模式,有助于初学者对Java代理模式的理解和运用。
逻辑交换代理开发移动应用的动态代理切换需要api后端概述 在使用 API 后端的移动应用程序开发中,如果您有多个登台端点服务器进行开发,通常很难切换 api 端点配置。 logical-switching-proxy是一个反向代理,通过...