Spring AOP的底层实现原理
Spring的两大核心之一就是AOP,AOP:面向切面编程。在说原理之前,得先知道一些 AOP的专业术语。
AOP的专业术语
连接点(JoinPoint):增强执行的位置(增加代码的位置),Spring只支持方法;
切点(PointCut):具体的连接点;一般可能通过一个表达式来描述;
增强(Advice):也称为消息,指的是增加的额外的代码,Spring中,增强除了包含代码外,还包含位置信息;
Spring中一共有四种增强:
- MethodBeforeAdvice:前置增强
- MethodInterceptor:环绕增强
- ThrowsAdvice:异常增强
- AfterReturingAdvice:返回值增强
引介(Introduction):特殊的增强,动态为类增加方法
织入(Weaving):将增强加入到目标类的过程,织入分为三种时期
- 编译器:AspectJ
- 类加载
- 运行期:jdk动态代理(实现接口),CGlib(子类,不能用final)
目标对象(Target):原始对象
代理对象(Proxy):加入了增强的对象,是生成的;
切面(Aspect):切点+增强
接下来我要说的就是在运行期间织入的两种实现方式
JDK动态代理(实现接口)
什么是代理模式呢?
代理模式有三个角色,分别是
- 抽象角色:接口
- 目标角色:实现类
- 代理角色:实现接口(InvocationHandler),并引用目标角色
代理模式与装饰者模式的区别
类图(结构)基本一样,但目的不同,装饰模式的前提是已经所有的类,并进行组装;
而使用代理模式时,我们不能直接访问目标角色或没有权限访问时,可以使用代理模式
代理模式分为两种
- 静态代理:需要为每个目标角色,创建一个对应的代理角色;类的数量会急剧膨胀
- 动态代理:自动为每个目标角色生成对应的代理角色
接下来就是jdk动态代理的代码:
实现jdk动态代理的前提是所有的目标类都必须要基于一个统一的接口
创建统一的接口
[java] view plain copy
package com.dao;
/**
* 为目标类定义统一的接口SleepDao
* @author XuXQ
*
*/
public interface SleepDao {
public void sleep();
}
定义目标对象
[java] view plain copy
package com.daoImpl;
import com.dao.SleepDao;
/**
* 目标类
* @author XuXQ
*
*/
public class SleepDaoImpl implements SleepDao {
@Override
public void sleep() {
System.out.println("本大人要睡觉了");
}
}
创建代理角色
[java] view plain copy
package com.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 创建的类得需要实现InvocationHandler,并重写invoke()方法
* InvocationHandler 是代理实例的调用处理程序 实现的接口
* 即:MyInvocationHandler 是代理实例的调用处理程序
* @author XuXQ
*
*/
public class MyInvoctionHandler implements InvocationHandler {
Object object=null;//目标对象
public MyInvoctionHandler(Object object) {
super();
this.object = object;
}
/**
* proxy=代理对象
* method=被调用方法的方法名
* args=被调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
System.out.println("睡觉前要脱衣服啊");
Object obj=method.invoke(object, args);//obj为目标对象调用方法的返回
值
System.out.println("睡着了当然得做个美梦啊");
return obj;
}
}
[java] view plain copy
编写测试用例
[java] view plain copy
package com.handler;
[java] view plain copy
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.dao.SleepDao;
import com.daoImpl.SleepDaoImpl;
public class Test1 {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void test() {
//目标类必须基于统一的接口
SleepDao s=new SleepDaoImpl();
ClassLoader classLoader=s.getClass().getClassLoader();
MyInvoctionHandler myInvoctionHandler=new MyInvoctionHandler(s);
//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
SleepDao sd=(SleepDao) Proxy.newProxyInstance(classLoader,
s.getClass().getInterfaces(), myInvoctionHandler);
//相当于调用代理角色的Invoke()
sd.sleep();
}
}
结果:
由结果可以看到成功的将增强织入到了目标对象中了
此处使用到了jdk的动态代理,invocationHandler,proxy,以及classloader在另外两篇文章有详解
InvocationHandler和Proxy(Class)的动态代理机制详解
http://www.cnblogs.com/shoshana-kong/p/9041485.html
http://www.cnblogs.com/shoshana-kong/p/9042013.html
2.CGlib代理
[java] view plain copy
package com.cglibproxy;
/**
* 和JDK动态代理不同,不需要创建统一的接口
* @author XuXQ
*
*/
public class Base {
public void sleep(){
System.out.println("本大少要睡觉啦");
}
}<strong>
</strong>
创建cglib的代理对象
[java] view plain copy
package com.cglibproxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//用来生成代理对象
public class CglibProxy implements MethodInterceptor {
public Object getProxy(Object object){
Enhancer e=new Enhancer();//创建代理对象类
e.setSuperclass(object.getClass());//声明代理对象的父类是谁(是目标
对象)
e.setCallback(this);//设置回调函数,即调用intercept()
return e.create();//返回创建的代理对象
}
/**
<span style="white-space:pre;"> </span> * proxy=代理对象,也是目标对象的子类
<span style="white-space:pre;"> </span> * args=方法参数
<span style="white-space:pre;"> </span> */
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
System.out.println("你个大懒猪,竟然睡觉前不脱衣服,嫌弃o");
Object object=arg3.invokeSuper(proxy, args);
System.out.println("起床啦,要不然得迟到了哦");
return null;
}
}
编写测试用例
[java] view plain copy
package com.cglibproxy;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
public class Test {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@org.junit.Test
public void test() {
CglibProxy proxy=new CglibProxy();
Base base=(Base) proxy.getProxy(new Base());
base.sleep();
}
}
结果:
由结果同样可以看到成功的将增强织入到了目标对象中了
此处涉及cglib相关知识
http://www.cnblogs.com/shoshana-kong/p/9041834.html
总结
当然我们以后写代码都是基于Aspect,直接写注解的,当然这并不代表这我们不需要知
道AOP
底层的实现原理,至于注解用的是哪种实现方式,使用配置来解决的,这里就不详解了
。
Spring AOP的底层实现原理的更多相关文章
- 漫画 | Spring AOP的底层原理是什么?
1.Spring中配置的bean是在什么时候实例化的? 2.描述一下Spring中的IOC.AOP和DI IOC和AOP是Spring的两大核心思想 3.谈谈IOC.AOP和DI在项目开发中的应用场景 ...
- Java AOP的底层实现原理
Java AOP的底层实现原理 一.什么是AOP 1.AOP:Aspect Oriented Programming(面向切面编程),OOP是面向对象编程,AOP是在OOP基础之上的一种更高级的设计思 ...
- (转)Spring AOP的底层实现技术
AOP概述 软件的编程语言最终的目的就是用更自然更灵活的方式模拟世界,从原始机器语言到过程语言再到面向对象的语言,我们看到编程语言在一步步用更自然.更强大的方式描述软件.AOP是软件开发思想的一个飞跃 ...
- Spring aop 原始的工作原理的理解
理解完aop的名词解释,继续学习spring aop的工作原理. 首先明确aop到底是什么东西?又如何不违单一原则并实现交叉处理呢? 如果对它的认识只停留在面向切面编程,那就脏了.从oop(Objec ...
- Spring Aop之Cglib实现原理详解
Spring Aop实现对目标对象的代理,AOP的两种实现方式:Jdk代理和Cglib代理.这两种代理的区别在于,Jdk代理与目标类都会实现同一个接口,并且在代理类中会调用目标类中被代理的方法,调用者 ...
- Spring的AOP的底层实现原理?
aop是ioc的一个扩展功能,先有的ioc,再有的aop,只是在ioc的整个流程中新增的一个扩展点而已:BeanPostProcessor 底层实现用的是动态代理 AOP应用场景 场景一: 记录日志 ...
- Spring笔记06(Spring AOP的底层实现动态代理)
1.代理模式readMe: 代理设计模式: 是java中常用的设计模式! 特点: .委托类和代理类有相同的接口或者共同的父类! .代理类为委托类负责处理消息,并将消息转发给委托类! .委托类和代理类对 ...
- Spring IOC的底层实现原理
PS:模块之间的相互依赖叫做耦合 传统方式的开发 UserService us=new UserService(); || v 面向接口编程 UserService us=new UserServi ...
- Spring AOP 实现原理与 CGLIB 应用
https://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/ AOP(Aspect Orient Programming),也就是面向 ...
随机推荐
- NVMe协议1.3c(一) 概述
刚开始接触NVMe,对此理解不深,如有错误敬请指出 1.1概述 NVM ExpressTM(NVMeTM)接口允许主机软件与非易失性存储器子系统通信. 此接口针对企业和客户端固态驱动器进行了优化,通常 ...
- python笔记11-元组
lis = ['127.0.0.1','3306']#列表tp = ('127.0.0.1','3306') #定义元组 lis[1]='3307'print(lis)print(tp[0])元祖也有 ...
- python自学第12天 模块定义,导入,内置模块
1.定义模块:用来从逻辑上组织python代码(实现一个功能),本质是.py结尾的python 包:本质就是一个目录(必须带有一个_init_.py文件)2.导入方法import module_nam ...
- Power BI中DAX的动态计算方差
我花了一点时间试图解决一个棘手的DAX表达式,那就是如何动态计算方差,下面我们认识一下这两个函数: PARALLELPERIOD 和 SAMEPERIODLASTYEAR 它能实现我们想要的结果, ...
- cocos2dx解决中文乱码方法
使用plist文件,优点方便做多国语言支持~也不用去做编码转换 1.Resource目录下新建text.plist文件,内容格式如下 <?xml version="1.0" ...
- s21day10 python笔记
s21day10 python笔记 一.函数补充 1.1 参数 基本参数知识 def get_list_date(aaa): #aaa:形式参数(形参) 任意个数 v = [11,22,33,44] ...
- Python全栈之路----函数进阶----生成器
生成器特点: 不能立即产生,取一次创建一次 只能往前走 等到走到最后,就会报错 >>> a = [i for i in range(1000)] >>> a [0, ...
- Hello2 分析
一.打开GreetingServlet.java文件以查看它 hello2应用程序是一个web模块,hello2应用程序的行为几乎与hello1应用程序相同,但是它是使用Java Servlet技术实 ...
- 快速排序的两种实现 -- 种轴partition : 比值partition(更精巧)
实现1:种轴partition,not in place--取定枢轴,将小于等于枢轴的放到枢轴左边,大于枢轴的放到右边 # python algorithm en_2nd edition p125de ...
- 20175202 《Java程序设计》第四周学习总结
20175202 <Java程序设计>第四周学习总结 第五章学习内容 1.子类的继承性: (1)子类与父类在同一包中的继承性:子类自然地继承了其父类中不是private的成员变量作为自己的 ...