利用cglib包实现Spring中aop的<aop:advisor>功能
一:前言
还有<aop:before>/<aop:after>/<aop:around>的没有实现,不过根<aop:advisor>是差不多的,就是要额外注册一些东西到AdvisorSupport里,这个等以后有时间再写了;
二:代码
1.Test类,用于描述<aop:pointcut的expression属性,即调用时这个类中声明的方法不会实施aop拦截
package me.silentdoer.aoprealization.action; /**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/28/18 2:50 PM
*/
public class Test {
public void printSS(){
System.out.println("UXXXXXXXXXXXss");
}
}
2.AopTest类,即aspect类(如StudentServiceImpl之类的)
package me.silentdoer.aoprealization.action; /**
* @author silentdoer
* @version 1.0
* @description 作为pointcut的提供类
* @date 4/27/18 8:14 PM
*/
public class AopTest extends Test{
public void foo(){
System.out.println("Hello, llll");
System.out.println(foo2(88));
} private String foo2(int num){
System.out.println(String.format("The string is %s", num));
return (num + 100) + "";
}
}
3.FooAdviceForAdvisor类,即advisor的实现类
package me.silentdoer.aoprealization.aop.advice; import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.Method; /**
* @author silentdoer
* @version 1.0
* @description 通过直接实现MethodInterceptor来实现Spring中的<aop:advisor ..></aop:advisor>
* @date 4/27/18 8:32 PM
*/
public class FooAdviceForAdvisor implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Before部分");
//System.out.println(methodInvocation.getClass());
Object result = methodInvocation.proceed();
System.out.println("After部分");
return result;
}
}
4.AopSupport类,实现用户配置和具体产生代理类分离的中间类(around/before/after配置也可以通过这种方式实现)
package me.silentdoer.aoprealization.aop.support; import me.silentdoer.aoprealization.aop.method.DefaultMethodInvocation;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
import java.util.List; /**
* @author silentdoer
* @version 1.0
* @description 这个类在实际中不允许用户主动使用
* @date 4/28/18 2:53 PM
*/
public class AopSupport implements MethodInterceptor {
private List<Method> pointcuts;
private org.aopalliance.intercept.MethodInterceptor advisor; @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
final Method met = method;
if (this.pointcuts.stream().anyMatch(m -> m.equals(met))){
DefaultMethodInvocation methodInvocation = new DefaultMethodInvocation();
methodInvocation.setTarget(o);
methodInvocation.setMethod(method); // 要通过适配器模式将MethodProxy转换为Method(Method是final无法适配,只好添加MethodProxy属性
methodInvocation.setRealMethod(methodProxy);
methodInvocation.setArgs(objects);
return advisor.invoke(methodInvocation);
}else{
return methodProxy.invokeSuper(o, objects);
}
} public void setPointcuts(List<Method> pointcuts) {
this.pointcuts = pointcuts;
} public void setAdvisor(org.aopalliance.intercept.MethodInterceptor advisor){
this.advisor = advisor;
}
}
5.DefaultMethodInvocation类,用于实现method/args/target的一体化
package me.silentdoer.aoprealization.aop.method; import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method; /**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/28/18 8:38 PM
*/
public class DefaultMethodInvocation implements MethodInvocation{
private Method method;
private MethodProxy realMethod;
private Object[] args;
private Object target; @Override
public Method getMethod() {
return this.method;
} @Override
public Object[] getArguments() {
return this.args;
} @Override
public Object proceed() throws Throwable {
return this.realMethod.invokeSuper(this.target, args);
} @Override
public Object getThis() {
return this.target;
} @Override
public AccessibleObject getStaticPart() {
return this.method;
} public void setMethod(Method method) {
this.method = method;
} public void setArgs(Object[] args) {
this.args = args;
} public void setTarget(Object target) {
this.target = target;
//System.out.println(this.target == null);
} public void setRealMethod(MethodProxy realMethod) {
this.realMethod = realMethod;
}
}
6.main方法所在类,兼具解析xml和装配代理类的作用(demo主要是为了了解aop的实现原理)
package me.silentdoer.aoprealization; import me.silentdoer.aoprealization.action.AopTest;
import me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor;
import me.silentdoer.aoprealization.aop.support.AopSupport;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List; /**
* @author silentdoer
* @version 1.0
* @description 这里就简单的实现advisor的aop,且expression默认是某个类中所有的declare的方法
* @date 4/27/18 4:56 PM
*/
public class Entrance {
private static Element root;
private static AopTest fooBean; public static void main(String[] args) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException {
org.dom4j.io.SAXReader reader = new SAXReader();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Document document = reader.read(classLoader.getResource("aop.xml"));
root = document.getRootElement();
List<Element> elements = root.elements(); Class beanClazz = classLoader.loadClass(elements.stream().filter((e) -> e.attributeValue("id").equals("aopTest")).findFirst().get().attributeValue("class"));
//System.out.println(beanClazz); //me.silentdoer.aoprealization.action.AopTest
// TODO 这个是没有加aop功能时原始的bean,这步可以理解为getBean
fooBean = (AopTest) beanClazz.newInstance();
fooBean.foo(); System.out.println("<------------------------------------------------------->"); // TODO 实现BeanFactoryPostProcessor接口的扫描配置文件来为对应的bean组装aop功能
Element config = elements.stream().filter(e -> e.getName().equals("config")).findFirst().get();
parseAopConfig(config);
// 动态代理类实现aop功能,但是对于非DeclaredMethod不会做切面拦截处理,比如在Test中的printSS方法;
fooBean.foo(); // 实现aop拦截
System.out.println("<---------------------------------------------------------------->");
fooBean.printSS(); // 不符合expression因此即便为fooBean配置了aop对于此方法也不会实施aop功能
} // 根据<aop:config来“重建”需要aop功能的bean,这里就是fooBean
private static void parseAopConfig(Element config){
// TODO 这里认定pointcut的expression是获取originBean的所有的DeclaredMethod方法
Element pointcutElem = config.element("pointcut");
List<Method> pointcuts = parsePointcuts(pointcutElem);
Element advisorElem = config.element("advisor");
// TODO 这里通过advisorElem得到用户自定义的advisor类对象
FooAdviceForAdvisor advisorBean = getUserAdvisor(advisorElem);
// TODO 根据advisor和pointcut组装成一个新的MethodInterceptor对象,这个interceptor是实现了expression和advisor联合的拦截者
MethodInterceptor realInterceptor = parseAdvisor(advisorBean, pointcuts);
// TODO 根据配置得知fooBean是需要加上aop功能,因此通过Enhancer重新生成新的bean覆盖老的bean,这步在Spring里是通过实现了BeanFactoryPostProcessor接口的类里执行的
fooBean = (AopTest) Enhancer.create(AopTest.class, realInterceptor);
} private static MethodInterceptor parseAdvisor(org.aopalliance.intercept.MethodInterceptor advisor, List<Method> pointcuts){
// 正式情况下AdvisorSupport是包访问权限,而这部分代码也是在和此类同一个包里面实现的因此AdvisorSupport是系统组件不由用户手动创建
AopSupport result = new AopSupport();
result.setAdvisor(advisor);
result.setPointcuts(pointcuts);
return result;
} private static List<Method> parsePointcuts(Element aopPointcut){
// TODO 本来应该通过aopPointcut的expression来获取,不过这个主要是实现aop对表达式的解析忽略
return Arrays.asList(AopTest.class.getDeclaredMethods());
} // 根据advisor-ref获取advisor对象
private static FooAdviceForAdvisor getUserAdvisor(Element advisor){
FooAdviceForAdvisor result = new FooAdviceForAdvisor();
return result;
}
}
7.aop.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:aop="silentdoer"> <!-- 模拟注册到Spring里管理,这里则只是简单的通过dom4j来搜索 -->
<bean id="aopTest" class="me.silentdoer.aoprealization.action.AopTest"/> <bean id="fooAdvisor" class="me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor"/>
<aop:config>
<!-- 这里暂且认为me.silentdoer.aoprealization.action.AopTest.*就是AopTest中所有Declared的方法 -->
<aop:poincut id="pointcut1" expression="me.silentdoer.aoprealization.action.AopTest.*"/>
<aop:advisor advisor-ref="fooAdvisor" poincut-ref="pointcut1"/>
</aop:config> <!--<bean id="fooAdvice" class="me.silentdoer.aoprealization.aop.advice.FooAdvice"/>
<aop:config>
<aop:pointcut id="pointcut2" expression="me.silentdoer.aoprealization.action.AopTest.*"/>
<aop:aspect ref="fooAdvice">
<aop:around method="around" poincut-ref="poincut2"/>
</aop:aspect>
</aop:config>-->
</beans>
利用cglib包实现Spring中aop的<aop:advisor>功能的更多相关文章
- Spring中IOC和AOP的详细解释(转)
原文链接:Spring中IOC和AOP的详细解释 我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入,和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂 ...
- spring中IOC和AOP原理
IoC(Inversion of Control): (1)IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中转 ...
- Spring中IOC和AOP的详细解释
我们是在使用Spring框架的过程中,其实就是为了使用IOC,依赖注入,和AOP,面向切面编程,这两个是Spring的灵魂. 主要用到的设计模式有工厂模式和代理模式. IOC就是典型的工厂模式,通过s ...
- 【转】Spring中事务与aop的先后顺序问题
[原文链接] http://my.oschina.net/HuifengWang/blog/304188 [正文] Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟sp ...
- spring中的多线程aop方法拦截
日常开发中,常用spring的aop机制来拦截方法,记点日志.执行结果.方法执行时间啥的,很是方便,比如下面这样:(以spring-boot项目为例) 一.先定义一个Aspect import org ...
- 对spring中IOC和AOP的理解
IOC:控制反转也叫依赖注入.利用了工厂模式. 为了方便理解,分解成每条以便记忆. 1.将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器 ...
- Spring中IOC和AOP的理解
IOC和AOP是Spring的核心 IOC:控制反转:将创建对象以及维护对象之间的关系由代码交给了spring容器进行管理,也就是创建对象的方式反转了,交由spring容器进行管理. DI:依赖注入: ...
- 解释Spring中IOC, DI, AOP
oc就是控制翻转或是依赖注入.通俗的讲就是如果在什么地方需要一个对象,你自己不用去通过new 生成你需要的对象,而是通过spring的bean工厂为你长生这样一个对象.aop就是面向切面的编程.比如说 ...
- 利用axure软件实现app中的轮播图功能
1.首先在axure软件中插入一张手机模型图片并调整为合适大小 2.在需要展示轮播图片位置拖入[动态面板]并且调整大小 拖入后双击动态面板,填入面板名称,并且添加面板状态(此处轮播图为三张,所以有三个 ...
随机推荐
- cloudera-hdfs 告警处理
2018-03-13 11:15:17,215 WARN [org.apache.flume.sink.hdfs.HDFSEventSink] - HDFS IO error org.apache.h ...
- mysql乐观锁总结和实践(二)
一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占 ...
- maven中导入包版本冲突的解决
导入struts包,在struts核心包的ognl包下存在javassist包: 然后再导入hibernate包,在hibernate核心下也存在javassist包: 这样便会存在冲突,ecplis ...
- BitCoinCore配置文件解读
bitcoin.conf 配置文件 除了 -datadir 和 -conf 以外的所有命令行参数都可以通过一个配置文件来设置,而所有配置文件中的选项也都可以在命令行中设置.命令行参数设置的值会覆盖配置 ...
- 使用开源的工具解析erspan流量
Decapsulation ERSPAN Traffic With Open Source Tools Posted on May 3, 2015 by Radovan BrezulaUpdated ...
- iOS.C
iOS开发中C语言的应用: 1. NS_ENUM & NS_OPTIONS http://nshipster.com/ns_enum-ns_options/
- 20172306《Java程序设计》第五周学习总结
20172306 2016-2017-2 <Java程序设计>第五周学习总结 教材学习内容总结 第五章主要学习了if以及while的语句的运用 运算符:== 代表相等,是两个之间的内存地址 ...
- 网页启用Gzip压缩 提高浏览速度
启用Gzip压缩的好处 它的好处显而易见,提高网页浏览速度,无论是之前说的精简代码.压缩图片都不如启用Gzip来的实在.下图为启用Gzip后的效果. Gzip压缩效率非常高,通常可以达到70%的压缩率 ...
- 一种基于URL数据源的WEB报表插件
完全支持所见所得的报表设计, 支持 PHP ,Java 等所有支持JSON格式的后端. 立即下载测试版本 需要正式版本?请QQ联系:1565498246 或者留言
- Creating Your Own PHP Helper Functions In Laravel
By Hamza Ali LAST UPDATED AUG 26, 2018 12,669 104 Laravel provides us with many built-in helper fun ...