Spring AOP 原理的理解
>AOP基本概念
1)通知(Advice):织入到目标类连接点上的一段程序代码。通知分为五种类型:
- Before:在方法被调用之前调用
- After:在方法完成后调用通知,无论方法是否执行成功
- After-returning:在方法成功执行之后调用通知
- After-throwing:在方法抛出异常后调用通知
- Around:通知了好、包含了被通知的方法,在被通知的方法调用之前后调用之后执行自定义的行为
2)切点(Pointcut):AOP通过“切点”定位特定的连接点
3)连接点(Joinpoint):程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。这些代码中的特定点,称为“连接点”。
4) 织入(Weaving):织入是将增强添加到目标类具体连接点上的过程。AOP有三种织入方式:
- 编译期织入,这要求使用特殊的Java编译器;
- 类装载期织入,这要求使用特殊的类装载器;
- 动态代理织入,在运行期为目标类添加增强生成子类的方式。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
5)切面(Aspect)切面由切点和通知组成,它既包括了横切逻辑的定义,也包括了连接点的定义
Spring 是切片流程
代理模式
就好比明星和经纪人,经纪人负责接活,负责明星唱歌前会场准备,明星唱歌后收钱。 代理类其实就是在代理对象,前后做了一些其他的处理, 这已经具备 AOP的轮廓了
静态代理模式栗子
// 接口
public interface IUserDao {
void save();
void find();
}
// 目标对象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模拟:保存用户!");
}
@Override
public void find() {
System.out.println("模拟:查询用户");
}
}
/**
* 静态代理 特点:
* 1. 目标对象必须要实现接口
* 2. 代理对象,要实现与目标对象一样的接口
*/
public class UserDaoProxy implements IUserDao {
// 代理对象,需要维护一个目标对象
private IUserDao target = new UserDao();
@Override
public void save() {
System.out.println("代理操作: 开启事务...");
target.save(); // 执行目标对象的方法
System.out.println("代理操作:提交事务...");
}
@Override
public void find() {
target.find();
}
}
public class StaticProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
IUserDao proxy = new UserDaoProxy();
proxy.save();
}
}
可以看到,静态代理是必须要有接口的,代理类和目标类都得事先接口,这样就显得很麻烦了,每次代理一个目标对象,就得做一个代理类,有没有一种方式,可以使用一个代理 ,代理多个目标对象呢?
动态代理模式栗子
动态代理不需要提前建立代理,而是在运行时,为目标对象动态生成代理类
// 接口
public interface IUserDao {
void save();
void find();
}
// 目标对象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模拟: 保存用户!");
}
@Override
public void find() {
System.out.println("查询");
}
}
/**
* 动态代理:JDK 动态代理采用的是反射机制实现
* 代理工厂,给多个目标对象生成代理对象!
*
*/
public class ProxyFactory {
// 接收一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 返回对目标对象(target)代理后的对象(proxy)
public Object getProxyInstance() {
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标对象使用的类加载器
target.getClass().getInterfaces(), // 目标对象实现的所有接口
new InvocationHandler() { // 执行代理对象方法时候触发
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 获取当前执行的方法的方法名
String methodName = method.getName();
// 方法返回值
Object result = null;
if ("find".equals(methodName)) {
// 直接调用目标对象方法
result = method.invoke(target, args);
} else {
System.out.println("开启事务...");
// 执行目标对象方法
result = method.invoke(target, args);
System.out.println("提交事务...");
}
return result;
}
}
);
return proxy;
}
}
public class JDKDynamicProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// 目标对象
IUserDao target = new UserDao();
// 创建代理类
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
System.out.println("代理对象: "+proxy.getClass());
proxy.save();
}
}
静态代理动态代理总结
可以总结一下,JDK 动态代理
// 创建代理类
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
实际上 隐藏了动态的去实现 目标对象的一个接口
class $jdkProxy implements IUserDao{}
也就是说 使用JDK 反射方式实现动态代理,目标对象必须实现一个接口,这就可能出现问题了,假设一个类,就是没有实现接口怎么办?
CGLIB实现动态代理实现栗子
CGLIB是使用继承的方式动态生成代理类,这个代理类是继承目标类的,这个就有个问题,需要目标类不被final修饰。
有点类似
public class UserDao{}
// CGLIB 是以动态生成的子类继承目标的方式实现,程序执行时,隐藏了下面的过程
public class $Cglib_Proxy_class extends UserDao{}
CGLIB实现
// 目标对象
public class UserDao {
public void save() {
System.out.println("模拟: 保存用户!");
}
public void find() {
System.out.println("查询");
}
}
public class CGLIBProxyFactory {
static class SimpleInterceptor implements MethodInterceptor {
/**
* @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[],
* org.springframework.cglib.proxy.MethodProxy)
*/
@Override
public Object intercept(Object target, Method methmod, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("entering " + methmod.getName());
Object result = proxy.invokeSuper(target, args);
System.out.println("leveaing " + methmod.getName());
return result;
}
}
public static T getProxy(Class cls) {
Enhancer enhancer = new Enhancer();
// 继承目标类
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
}
public class CGLIBProxyTest {
public static void main(String[] args) {
//生成代理 没有接口
UserDao proxy = (UserDao) CGLIBProxyFactory.getProxy(UserDao.class);
System.out.println("代理类:"+ proxy.getClass());
proxy.save();
}
}无锡正规妇科医院 http://www.jlfukeyy.com/
JDK和CGLIB的区别
1.上面可以可以看到 CGLIB是不需要 目标对象实现接口的, CGLIB是通过继承来实现的
2. JDK动态代理是需要一个具体的目标对象的,但是CGLIB是不需要这么一个具体对象的
Spring AOP 是怎样实现的呢?
1.AOP 是基于动态代理模式
2.AOP是方法级别的
3.AOP可以分类业务代码和关注点代码(日志,事务等)
AOP 是什么时候生成代理的?
AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表;而动态代理则以 Spring AOP 为代表
IOC容器BeanDefinitionMap里面结构看内容是啥
bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#2=Root
bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#3=Root
bean:class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#0=Root
Spring AOP 原理的理解的更多相关文章
- 面试问烂的 Spring AOP 原理、SpringMVC 过程(求求你别问了)
Spring AOP ,SpringMVC ,这两个应该是国内面试必问题,网上有很多答案,其实背背就可以.但今天笔者带大家一起深入浅出源码,看看他的原理.以期让印象更加深刻,面试的时候游刃有余. Sp ...
- Spring学习总结(1)——Spring AOP的概念理解
1.我所知道的aop 初看aop,上来就是一大堆术语,而且还有个拉风的名字,面向切面编程,都说是OOP的一种有益补充等等.一下子让你不知所措,心想着:怪不得 很多人都和我说aop多难多难 .当我看进去 ...
- spring aop原理分析
持续更新... aop跟java代理模式有关. java.lang.reflect.Proxy java.lang.reflect.InvocationHandler 工厂模式用到java反射. ao ...
- aop原理及理解
概念 Aspect Oriented Programming,面向切面编程,实际上它是一个规范.一种设计思路,总之是抽象的. 先上图 使用目的 从项目结构上来说 对业务逻辑的各个部分进行隔离,降低业务 ...
- Spring AOP原理(续)
十二.AOP 1. 说出Spring的通知类型有哪些? spring共提供了五种类型的通知: 通知类型 接口 描述 Around 环绕通知 org.aopalliance.intercept.Meth ...
- Spring Boot -- Spring AOP原理及简单实现
一.AOP基本概念 什么是AOP,AOP英语全名就是Aspect oriented programming,字面意思就是面向切面编程.面向切面的编程是对面向对象编程的补充,面向对象的编程核心模块是类, ...
- spring ioc 原理 spring aop原理
大家一直都说spring的IOC如何如何的强大,其实我倒觉得不是IOC如何的强大,说白了IOC其实也非常的简单.我们先从IOC说起,这个概念其实是从我们平常new一个对象的对立面来说的,我们平常使用对 ...
- spring aop 原理学习
@EnableAspectJAutoProxy: @Import(AspectJAutoProxyRegistrar.class) 实际是创建了一个以org.springframework.aop.c ...
- spring aop原理和实现
一.aop是什么 1.AOP面向方面编程基于IoC,是对OOP的有益补充: 2.AOP利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可 ...
随机推荐
- pc端常用电脑屏幕 ((响应式PC端媒体查询)电脑屏幕分辨率尺寸大全)
PC端************ 按屏幕宽度大小排序(主流的用橙色标明) 分辨率 比例 | 设备尺寸 1024*500 (8.9寸) 1024*768 (比例4:3 | 10.4寸.12.1寸.1 ...
- sessionid 特性
本文为博主原创,转载请注明出处: sessionid 是服务器用来辨别客户端浏览器身份的号码,就像人的身份证一样.当用户第一次访问网站时,服务器会分配一个独一无二的 sessionid 给用户浏览器: ...
- SpringMVC 事件监听 ApplicationListener
1. 实现 ApplicationListener<T> 接口(T为监听类型,稍后会列出具体可监听事件) 2. 将该自定义监听类,注册为Spring容器组件.(即将该类注入Spring容器 ...
- 946. Validate Stack Sequences
946. Validate Stack Sequences class Solution { public: bool validateStackSequences(vector<int> ...
- matlab学习笔记12单元数组和元胞数组 cell,celldisp,iscell,isa,deal,cellfun,num2cell,size
一起来学matlab-matlab学习笔记12 12_1 单元数组和元胞数组 cell array --cell,celldisp,iscell,isa,deal,cellfun,num2cell,s ...
- UltraEdit 替换符
1.在每行的最后一行添加字符串: 打开替换,在查找中输入 ^r 在替换栏中输入要替换的字符 再把下边的正则表达式勾选,然后开始或是全部替换就可以了 2.替换回车换行 在查找中输入 要替换的字符 ...
- c# 导出excel的三种方式
第一种:流导出 SaveFileDialog exe = new SaveFileDialog(); exe.Filter = "Execl files (*.xls)|*.xls" ...
- 使用epoll实现一个udp server && client
udp server #!/usr/bin/env python #-*- coding:utf-8 -*- import socket import select import Queue #创建s ...
- vs2017 vs2019 打开cs文件提示无法识别的GUID格式
总结一句话 no zuo no die. 是我自己在注册表中给vs增加了自动以管理员身份运行,把值给错了,弄成了 ~ RUNASADMIN WIN7RTM, 改成 ~ RUNASADMIN 后OK.还 ...
- Oracle Spatial分区应用研究之八:不同分区粒度在1.5亿要素量级下的查询性能
以土地调查地类图斑层作为测试数据,共计约1.5亿条要素.随机生成90次各比例尺的查询范围,在ORACLE 11gr2数据库中进行空间查询,记录查询耗时.最后计算平均值和第90百分位数,结果如下图所示: ...