动态代理的演示

[b]使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口[/b]

定义两个接口

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();

}

}




[b]CglibTest[/b]

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();
}

}


[b]Intercept[/b]

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;
}

}


[b]业务逻辑[/b]

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");
}

}


[b]3.4 字节码转换 [/b]
自定义的类加载器实现AOP只能拦截自己加载的字节码,那么有没有一种方式能够监控所有类加载器加载字节码呢?有,使用Instrumentation,它是 Java 5 提供的新特性,使用 Instrumentation,开发者可以构建一个字节码转换器,在字节码加载前进行转换。本节使用Instrumentation和javassist来实现AOP。

[b]3.4.1 构建字节码转换器[/b]
首先需要创建字节码转换器,该转换器负责拦截Business类,并在Business类的doSomeThing方法前使用javassist加入记录日志的代码。


4 AOP实战
说了这么多理论,那AOP到底能做什么呢? AOP能做的事情非常多。
[b]性能监控[/b],在方法调用前后记录调用时间,方法执行太长或超时报警。
[b]缓存代理[/b],缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。
[b]软件破解[/b],使用AOP修改软件的验证类的判断逻辑。
[b]记录日志[/b],在方法执行前后记录系统日志。
[b]工作流系统[/b],工作流系统需要将业务代码和流程引擎代码混合在一起执行,那么我们可以使用AOP将其分离,并动态挂接业务。
[b]权限验证[/b],方法执行前验证是否有权限执行当前方法,没有则抛出没有权限执行异常,由业务代码捕捉。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CGlib是一个针对Java字节码的代码生成库,它可以在运行时扩展Java类和实现接口的功能。它通过生成目标类的子类来实现代理,从而实现了动态代理的功能。 在使用CGlib动态代理时,首先需要添加CGlib库的依赖。然后,创建一个Enhancer对象,并设置被代理类作为目标类。接下来,可以通过调用Enhancer对象的方法来设置回调函数和拦截器等。最后,使用Enhancer对象的create方法生成代理类的实例。 以下是一个简单的示例代码,演示了如何使用CGlib动态代理: ```java import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class Main { public static void main(String[] args) { // 创建Enhancer对象 Enhancer enhancer = new Enhancer(); // 设置被代理类 enhancer.setSuperclass(TargetClass.class); // 设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 在方法调用前进行拦截处理 System.out.println("Before method: " + method.getName()); // 调用被代理类的方法 Object result = proxy.invokeSuper(obj, args); // 在方法调用后进行拦截处理 System.out.println("After method: " + method.getName()); return result; } }); // 生成代理类的实例 TargetClass proxy = (TargetClass) enhancer.create(); // 调用代理类的方法 proxy.doSomething(); } } class TargetClass { public void doSomething() { System.out.println("Doing something..."); } } ``` 在上面的示例中,我们创建了一个名为TargetClass的被代理类。然后使用CGlib动态代理生成了一个代理类的实例,并通过调用代理类的方法来间接调用被代理类的方法。在方法调用前后,我们可以通过设置回调函数来添加额外的处理逻辑。 需要注意的是,CGlib动态代理是通过继承来实现的,因此对于final类和方法无法进行代理。另外,由于CGlib是基于字节码操作实现的,所以在生成代理类的过程中会比较耗时。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值