博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入探索spring技术内幕(五): 剖析spring AOP工作原理
阅读量:7029 次
发布时间:2019-06-28

本文共 5346 字,大约阅读时间需要 17 分钟。

hot3.png

一、前言

AOP (Aspect Oriented Programing) - 面向切面编程,它主要用于日志记录、性能分析、安全控制、事务处理、异常处理等方面。

AOP主要使用JDK的反射和动态代理,AOP代理其实是由AOP框架动态生成的一个对象,该对象可作为目标对象使用,AOP代理包含了目标对象的全部方法,但AOP代理的方法与目标对象的方法存在差异:AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。

 

动态代理的文章请参考:

二、实现细节

下面这个例子利用AOP来实现日志记录:

附上一张类的结构图,该例子需要导入dom4j.jar

①业务逻辑接口

/** * 业务逻辑类接口 * @author zhangjim */public interface BusinessService {	/**	 * 处理业务	 */	public void process();}

② 业务逻辑实现

/** * 业务逻辑对象实现类 * @author zhangjim */public class BusinessServiceImpl implements BusinessService {	/**	 * 处理业务	 */	public void process() {		System.out.println("process business logic...");	}}

③ 通知类接口

/** * 通知类接口 * @author zhangjim */public interface Advisor {	/**	 * 所做的操作	 */	public void doInAdvisor(Object proxy, Method method, Object[] args);}

④ 方法的前置通知

import java.lang.reflect.Method;/** * 方法前置通知,它完成方法的前置操作 * @author zhangjim */public class BeforeMethodAdvisor implements Advisor {	/**	 * 在方法执行前所进行的操作	 */	public void doInAdvisor(Object proxy, Method method, Object[] args) {		System.out.println("before process... ");	}}

⑤ 方法的后置通知

/** * 方法的后置通知,它完成方法的后置操作 * @author zhangjim */public class AfterMethodAdvisor implements Advisor {	/**	 * 在方法执行后所进行的操作	 */	public void doInAdvisor(Object proxy, Method method, Object[] args) {		System.out.println("after process...");	}}

⑥ AOP处理器

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import com.zdp.advisor.Advisor;/** * AOP处理器 * @author zhangjim */public class AopHandler implements InvocationHandler {	private Object target; // 需要代理的目标对象	Advisor beforeAdvisor; // 方法前置通知	Advisor afterAdvisor; // 方法后置通知	/**	 * 设置代理目标对象,并生成动态代理对象.	 * @param target 代理目标对象	 * @return 返回动态代理对象	 */	public Object setObject(Object target) {		this.target = target; // 设置代理目标对象 		Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); // 根据代理目标对象生成动态代理对象		return proxy;	}	/**	 * 若定义了前置处理,则在方法执行前执行前置处理, 若定义了后置处理,则在方法调用后调用后置处理.	 * 	 * @param proxy 代理对象	 * @param method 调用的业务方法	 * @param args 方法的参数	 * @return 返回结果信息	 * @throws Throwable	 */	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {		if (beforeAdvisor != null) { 			beforeAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的前置处理		}		method.invoke(target, args); // 执行业务方法		if (afterAdvisor != null) {			afterAdvisor.doInAdvisor(proxy, method, args); // 进行业务方法的后置处理		}		return null; // 返回结果对象	}	/**	 * 设置方法的前置通知	 * @param advisor 方法的前置通知	 */	public void setBeforeAdvisor(Advisor advisor) {		this.beforeAdvisor = advisor;	}	/**	 * 设置方法的后置通知	 * @param advisor 方法的后置通知	 */	public void setAfterAdvisor(Advisor advisor) {		this.afterAdvisor = advisor;	}}

⑦ Bean工厂类

import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import com.zdp.advisor.Advisor;/** * Bean工厂类 * @author zhangjim */public class BeanFactory {	private Map
beansMap = new HashMap
(); /** * Bean工厂的初始化 */ public void init(String xml) { try { SAXReader reader = new SAXReader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream ins = classLoader.getResourceAsStream(xml); // 读取指定的配置文件 Document doc = reader.read(ins); Element root = doc.getRootElement(); AopHandler aopHandler = new AopHandler(); // 创建AOP处理器(动态生成的proxy类中持有了aopHandle的引用) for (Iterator iter = root.elementIterator("bean"); iter.hasNext();) { // 遍历bean Element element = (Element) iter.next(); Attribute id = element.attribute("id"); // 获取bean的属性id、class、aopClass、aopType Attribute cls = element.attribute("class"); Attribute aopClass = element.attribute("aopClass"); Attribute aopType = element.attribute("aopType"); if (aopClass != null && aopType != null) { // 如果配置了aopClass和aopType属性时,需进行拦截操作 Class advisorClass = Class.forName(aopClass.getText()); // 根据aopClass字符串获取对应的类 Advisor advisor = (Advisor) advisorClass.newInstance(); // 创建该类的对象 if ("before".equals(aopType.getText())) { // 根据aopType的类型来设置前置或后置顾问 aopHandler.setBeforeAdvisor(advisor); } else if ("after".equals(aopType.getText())) { aopHandler.setAfterAdvisor(advisor); } } Class clazz = Class.forName(cls.getText()); // 利用Java反射机制,通过class的名称获取Class对象 Object obj = clazz.newInstance(); // 创建一个对象 Object proxy = (Object) aopHandler.setObject(obj); // 产生代理对象proxy beansMap.put(id.getText(), proxy); // 将对象放入beansMap中,其中id为key,对象为value } } catch (Exception e) { System.out.println(e.toString()); } } /** * 通过bean的id获取bean的对象. * @param beanName bean的id * @return 返回对应对象 */ public Object getBean(String beanName) { Object obj = beansMap.get(beanName); return obj; }}

⑧ 配置文件beans.xml

⑨ 测试类

import com.zdp.service.BusinessService;import com.zdp.spring.BeanFactory;/** * 测试类 * @author zhangjim */public class Client {	public static void main(String[] args) {		BeanFactory beanFactory = new BeanFactory();  		beanFactory.init("beans.xml");		BusinessService proxy = (BusinessService) beanFactory.getBean("businessService");		proxy.process();	}}

三、小结

上文仅仅是简单地模拟了的AOP的实现,但还是很好地展现了JDK反射和动态代理在spring中的应用,对于初学者理解AOP应该会有一点帮助。 

源码下载地址: 

参考资料:

转载于:https://my.oschina.net/u/2381372/blog/761778

你可能感兴趣的文章
[原]Unity3D深入浅出 - 脚本开发基础(Scripts)
查看>>
HTTP Error 503. The service is unavailable
查看>>
常用的排序、查找算法的时间复杂度和空间复杂度
查看>>
Android 检测SD卡状态
查看>>
SQL Server 查询所有包含某文本的存储过程、视图、函数
查看>>
Error response from daemon: conflict: unable to remove repository reference 解决方案
查看>>
【Dijkstra】CCF201609-4 交通规划
查看>>
loadRunner11的安装过程
查看>>
boost-同步-锁选项
查看>>
随机过程(方兆本,缪伯其)读书笔记-第一章-引论
查看>>
Wireless Penetration Testing (1-6 chapter)
查看>>
二分查找
查看>>
大嫂的HTML
查看>>
获取元素的宽高和位置(转自脚本之家)
查看>>
对于yum中没有的源的解决办法-EPEL
查看>>
web安全问题总结
查看>>
使用VMware 管理服务器
查看>>
初学 python 之 用户登录实现过程
查看>>
Spark性能调优
查看>>
BOS中控件非空 非0校验
查看>>