利用Cglib实现AOP
前文讲了, 可以利用Spring, Guice等框架提供的容器实现AOP, 如果想绕过容器, 直接注入Class,
可以利用Cglib为对象加上动态代理,实现代码切入, 但是每次调用比较繁琐,
因此我们还需要给他加了一层语法糖, 使之更易用.
Advice
Spring带了一堆Advice, 我们只模拟实现环绕Advice, 以及增加了一个Clear切入的注解, 下面看具体实现.
/**
* 环绕Advie
*
* 可以加在类上, 或者方法上.
* 加在类上的话, 类中所有无@Clear注解的方法都会被切入
*
* @Before({CustomInterceptor.class, B.class})
* @Before(CustomInterceptor.class)
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Before {
Class<? extends Interceptor>[] value();
}
/**
* 清除Advice
*
* 可以清除方法上的指定Interceptor, 若不指定, 则清除所有切入.
*
* @Clear 清除所有
* @Clear(CustomInterceptor.class) 清除CustomInterceptor
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Clear {
Class<? extends Interceptor>[] value() default {};
}
语法糖
直接调用Cglib做切入, 需要setSuperClass, setCallback等等.
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(AopDemo.class);
enhancer.setCallback(new MethodInterceptorImpl()); AopDemo demo = (AopDemo) enhancer.create();
我们需要对Enhancer以及Callback进行封装, 减少复杂度
import java.util.concurrent.ConcurrentHashMap; /**
* cglib中Enhancer的语法糖, 让注入更简单点
*/
public class Enhancer { private static final ConcurrentHashMap<String, Object> singleton = new ConcurrentHashMap<String, Object>(); private Enhancer(){} public static <T> T enhance(Class<T> targetClass) {
return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback());
} public static <T> T enhance(Class<T> targetClass, Interceptor... injectInters) {
return (T)net.sf.cglib.proxy.Enhancer.create(targetClass, new Callback(injectInters));
} public static <T> T getTarget(String singletonKey) {
return (T)singleton.get(singletonKey);
} public static <T> T enhance(String singletonKey, Class<T> targetClass) {
Object target = singleton.get(singletonKey);
if (target == null) {
target = enhance(targetClass);
singleton.put(singletonKey, target);
}
return (T)target;
} public static <T> T enhance(String singletonKey, Class<T> targetClass, Interceptor... injectInters) {
Object target = singleton.get(singletonKey);
if (target == null) {
target = enhance(targetClass, injectInters);
singleton.put(singletonKey, target);
}
return (T)target;
}
public static <T> T enhance(Object target) {
return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target));
} public static <T> T enhance(Object target, Interceptor... injectInters) {
return (T)net.sf.cglib.proxy.Enhancer.create(target.getClass(), new Callback(target, injectInters));
}
public static <T> T enhance(String singletonKey, Object target) {
Object result = singleton.get(singletonKey);
if (result == null) {
result = enhance(target);
singleton.put(singletonKey, result);
}
return (T)result;
} public static <T> T enhance(String singletonKey, Object target, Interceptor... injectInters) {
Object result = singleton.get(singletonKey);
if (result == null) {
result = enhance(target, injectInters);
singleton.put(singletonKey, result);
}
return (T)result;
} } import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set; /**
* Callback.
*/
class Callback implements MethodInterceptor { private Object injectTarget = null;
private final Interceptor[] injectInters; private static final Set<String> excludedMethodName = buildExcludedMethodName();
private static final InterceptorManager interMan = InterceptorManager.me(); public Callback() {
this.injectInters = InterceptorManager.NULL_INTERS;
} public Callback(Interceptor... injectInters) {
checkInjectInterceptors(injectInters);
this.injectInters = injectInters;
} public Callback(Object injectTarget, Interceptor... injectInters) {
if (injectTarget == null) {
throw new IllegalArgumentException("injectTarget can not be null.");
}
checkInjectInterceptors(injectInters);
this.injectTarget = injectTarget;
this.injectInters = injectInters;
} private void checkInjectInterceptors(Interceptor... injectInters) {
if (injectInters == null) {
throw new IllegalArgumentException("injectInters can not be null.");
}
for (Interceptor inter : injectInters) {
if (inter == null) {
throw new IllegalArgumentException("interceptor in injectInters can not be null.");
}
}
} public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (excludedMethodName.contains(method.getName())) {
// if (method.getName().equals("finalize"))
// return methodProxy.invokeSuper(target, args);
// return this.injectTarget != null ? methodProxy.invoke(this.injectTarget, args) : methodProxy.invokeSuper(target, args); // 保留上面注释部分,此处为优化
if (this.injectTarget == null || method.getName().equals("finalize")) {
return methodProxy.invokeSuper(target, args);
} else {
return methodProxy.invoke(this.injectTarget, args);
}
} if (this.injectTarget != null) {
target = this.injectTarget;
Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, target.getClass(), method);
Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
invocation.useInjectTarget = true;
invocation.invoke();
return invocation.getReturnValue();
}
else {
Class<?> targetClass = target.getClass();
if (targetClass.getName().indexOf("$$EnhancerByCGLIB") != -1) {
targetClass = targetClass.getSuperclass();
}
Interceptor[] finalInters = interMan.buildServiceMethodInterceptor(injectInters, targetClass, method);
Invocation invocation = new Invocation(target, method, args, methodProxy, finalInters);
invocation.useInjectTarget = false;
invocation.invoke();
return invocation.getReturnValue();
}
} private static final Set<String> buildExcludedMethodName() {
Set<String> excludedMethodName = new HashSet<String>();
Method[] methods = Object.class.getDeclaredMethods();
for (Method m : methods) {
excludedMethodName.add(m.getName());
}
// getClass() registerNatives() can not be enhanced
// excludedMethodName.remove("getClass");
// excludedMethodName.remove("registerNatives");
return excludedMethodName;
}
}
封装后可以直接使用一句话, 还可用来增强已有对象
AopDemo demo = Enhancer.enhance(AopDemo.class);
示例
@Before({PrivilegeInterceptor.class, LogInterceptor.class})
public class AopDemo { public static void main(String[] args){
AopDemo demo = Enhancer.enhance(AopDemo.class);
demo.doSomething();
demo.doOtherthing(); } public void doOtherthing() {
// 默认沿用Class的interceptor
System.out.println("do 111111111111111");
} @Clear(PrivilegeInterceptor.class)
public void doSomething() {
// 手动清除了权限Interceptor
System.out.println("do 222222222222222");
}
}
public class LogInterceptor implements Interceptor{
@Override
public void intercept(Invocation inv) {
inv.invoke();
System.out.println("Log记录入库");
}
} public class PrivilegeInterceptor implements Interceptor{
@Override
public void intercept(Invocation inv) {
System.out.println("鉴权成功");
inv.invoke();
}
}
doOtherthing执行结果
鉴权成功
do 111111111111111
Log记录入库
doSomething执行结果
do 222222222222222
Log记录入库
其他使用
直接用来增强对象
AopDemo demoSinle1 = Enhancer.enhance(AopDemo.getInstance());
在enhance里new Interceptor
AopDemo demo3 = Enhancer.enhance(AopDemo.class, new Interceptor() {
@Override
public void intercept(Invocation inv) {
System.out.println("new before");
inv.invoke();
System.out.println("new after");
}
});
demo3.doSomething();
在需要增强的方法上写@Before
@Before(LogInterceptor.class)
public void doOtherthing() {
}
利用Cglib实现AOP的更多相关文章
- (转)使用CGLIB实现AOP功能与AOP概念解释
http://blog.csdn.net/yerenyuan_pku/article/details/52864395 使用CGLIB实现AOP功能 在Java里面,我们要产生某个对象的代理对象,这个 ...
- 利用cglib生成动态java bean
cglib详细学习 http://blog.csdn.net/u010150082/article/details/10901641 cglib-nodep jar报下载 http://grepcod ...
- 利用C#实现AOP常见的几种方法详解
利用C#实现AOP常见的几种方法详解 AOP面向切面编程(Aspect Oriented Programming) 是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. 下面这篇文章主要 ...
- Spring进阶之路(10)-Advice简单介绍以及通过cglib生成AOP代理对象
Advice简单介绍 1. Before:在目标方法运行之前运行织入.假设Before的处理中没有进行特殊的处理.那么目标方法终于会运行,可是假设想要阻止目标方法运行时.能够通过抛出一个异常来实现.B ...
- 利用CGLib实现动态代理实现Spring的AOP
当我们用Proxy 实现Spring的AOP的时候, 我们的代理类必须实现了委托类的接口才能实现. 而如果代理类没有实现委托类的接口怎么办? 那么我们就可以通过CGLib来实现 package cn. ...
- 利用cglib包实现Spring中aop的<aop:advisor>功能
一:前言 还有<aop:before>/<aop:after>/<aop:around>的没有实现,不过根<aop:advisor>是差不多的,就是要额 ...
- ssm+redis 如何更简洁的利用自定义注解+AOP实现redis缓存
基于 ssm + maven + redis 使用自定义注解 利用aop基于AspectJ方式 实现redis缓存 如何能更简洁的利用aop实现redis缓存,话不多说,上demo 需求: 数据查询时 ...
- JAVA动态代理和方法拦截(使用CGLib实现AOP、方法拦截、委托)
AOP用CGLib更简便.更可控. 动态代理的实现非常优雅. 实体类: public class SampleClass { public String MyFunction1(String inpu ...
- Java入门到精通——调错篇之Spring2.5利用aspect实现AOP时报错: error at ::0 can't find referenced pointcut XXX
一.问题描述及原因. 利用Aspect注解实现AOP的时候出现了error at ::0 can't find referenced pointcut XXX.一看我以为注解写错了,结果通过查询相关资 ...
随机推荐
- HTML5-svg圆形饼状图进度条实现原理
<svg width="440" height="440" viewbox="0 0 440 440"> <circle ...
- 微信小程序(一)
开发流程 注册微信小程序并申请微信支付-->制作小程序-->上传并提交审核-->审核通过,小程序上线 开发微信小程序需要准备 企业公众号(被认证)以及申请小程序.微信开发技术.S ...
- php的ob函数实现页面静态化
首先介绍一下php中ob缓存常用到的几个常用函数ob_start():开启缓存机制ob_get_contents():获取ob缓存中的内容ob_clean()清除ob缓存中的内容,但不关闭缓存ob_e ...
- 项目中AppDelegate详解
1.AppDelegate.h //模板默认引入程序需要使用“类”的框架,即UIKit.h头文件,使它包含在程序中 #import <UIKit/UIKit.h> //此处@class声明 ...
- 【BZOJ3529】【SDOI2014】 数表
Time Limit: 10 Sec Memory Limit: 512 MB Description 有一张\(n×m\)的数表,其第i行第j列(\(,1 \le i \leq n,1 \le ...
- 微信企业号JS-SDK选择图片、上传图片
因公司项目需要,要修改一个手机端上传图片的一个功能,原本的项目用的是input 的file控件上传的,虽然标注了可以多选,但是在实际运用当中只有iOS手机可以实现多选,Android手机并不支持多选, ...
- JLINK 10针J和20针JTAG接口连接方法
我的JLINK终于用上了,哈哈,好开心,终于不用考虑是不是要借用别人的PC机了,昨天到城隍庙电子市场忙活了一下午,终于算是满载而归,呵呵,好了,下面说一下接法,其实根本不需要什么转接板什么的,直接把相 ...
- dojo拼接成CSV格式字符串
var student = "学号,姓名,年龄\n"; for(var i = 0;i<resp.items.length;i++) { student += resp.it ...
- 项目部署到Tomcat报错
1.今天晚上,我想把dojo项目部署到Tomcat中,结果发现部署不了,Tomcat报错.而且,这个错误白天时也碰到了. 错误具体详细如下: Publishing failed with multip ...
- R语言自动化报告格式——knitr
R语言自动化报告格式--knitr 相关文献: R语言自动化报告格式--knitr 资讯 | R Notebooks 即将发布 ------------------------------------ ...