Spring框架——AOP代理
我们知道AOP指的就是设计模式中的代理模式。
一种是静态代理,高效,但是代码量偏大;
另一种就是动态代理,常见的有SDK下的动态代理,和CGLIB的动态代理,此外呢,还有注解式代理等等。
Spring框架下的AOP内容确实很多,也只能讲很多,没办法一一罗列,
本文例举的是Bean函数执行时候的一些代理。
AOP核心概念
我们自己写AOP会轻松很多,更加自由,而Spring对AOP进行了细致的划分,这种划分方式是被大部分企业所接受的,了解并使用Spring自身的AOP,可以降低集成其它框架的难度。
下面介绍一些专有名词。
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
就如图所示,程序流程会按顺序执行,而切面就像一个平面,在这个流程中间插入,这种插入对原先代码是无破坏性的,不需要修改原先代码即可实现。
3、连接点(joinpoint)
被拦截到的点,它可以是程序执行过程中的任意一点,而AOP主要做的是方法上的拦截。
4、切入点(pointcut)
对连接点进行拦截的定义,切面与流程的交点。
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
AOP的分类(增强分类)
此处的标题提到了增强,什么是增强?其实就是AOP了,至于为什么这么取名,只能问我们的前辈了,我见到就有这个名词了……
通常认为Spring在Bean的配置中有5种类型增强(根据英译,我认为应当是3种增强,2种拦截)。
代码上的直观感受就是五个接口了:
前置增强:org.springframework.aop.BeforeAdvice,其中BeforeAdvice是一个空接口,MethodBeforeAdvice是目前可用的前置增强,这个接口中实现前置方法。
后置增强:org.springframework.aop.AfterReturningAdvice,这个接口中要实现后置方法。
异常抛出增强:org.springframework.aop.ThrowsAdvice,代表抛出异常增强,此接口的函数在异常的时候执行。
环绕增强(方法拦截):org.aopalliance.intercept.MethodInterceptor,直译上看,它应该叫方法拦截,也就是说实现这个接口,可以不让我们的方法执行。
引介增强:org.springframework.aop.IntroductionInterceptor,IntroductionInterceptor的方法只有一个Class参数,并不十分方便使用,可以直接继承DelegatingIntroductionInterceptor类。它也是一种拦截方法,可以使用表示在目标类中添加一些新的方法和属性。
源码
环绕增强(拦截器)
这个和传统的JDK代理和CGLIB代理最类似,这里你可以获取到你需要调用的方法,你要是想放弃使用前置增强和后置增强,将它们的代码全部放在这里执行,这也是可以的。
具体的使用呢,就比如说:你要做一件很耗内存的操作,执行那个操作之前,你要判断内存容量,要是内存不足了,就放弃对方法的使用,这样的代码逻辑就可以放到这里。
/**
* 这是一个拦截器,在某些情况下,选择放弃对方法的使用,其实在这里编写前置代理和后置代理也可以,但是Spring既然提供了其他接口,参照接口实现更加规范
* @author ChenSS
* @2017年1月1日
*/
public class MyMethodInterceptor implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation dao) throws Throwable {
System.out.println("MyMethodInterceptor执行");
// TODO 方法执行前要做的事情
//如果说,不执行下面这一行代码,则目标方法将不执行,其他的增强效果也全部失效
Object result= dao.proceed();
// TODO 方法执行后要做的事情
return result;
}
}
前置代理
/**
* 前置增强,也就是说这些代码会在你需要调用的那个方法之前执行
* @author ChenSS
* @2017年1月1日
*/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法执行之前");
}
}
后置增强
/**
* 后置增强,这些代码会在你需要调用的那个方法之后执行
* @author ChenSS
* @2017年1月1日
*/
public class MyAfterReturningAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法执行结束");
}
}
异常抛出增强
/**
* 这个接口实际是一个空的接口,但是方法体还是得参照规范写,具体捕捉什么异常要写清楚
* @author ChenSS
* @2017年1月1日
*/
public class MyThrowsAdvice implements ThrowsAdvice{
/**
* 笼统地使用了Exception,可以做具体的异常捕捉
*/
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
System.out.println(method.getName()+"出现异常");
}
}
引介增强
/**
* 这个呢,也是一种拦截方法,也可以拦截方法的执行,
* @author ChenSS
* @2017年1月1日
*/
public class MyIntroductionInterceptor extends DelegatingIntroductionInterceptor{
private static final long serialVersionUID = 2582891122340903718L;
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("引介增强启动拦截");
return super.invoke(mi);
}
}
测试函数
这里直接使用硬编码的方式进行测试,具体的Spring配置可以参考其它博主的文章。
目前大部分框架都封装得接近完美,加上注解的使用,实际编码过程中,使用的可能性约等于零;
但是如果自己写框架,需要的时候是真的有用,这篇文章我自己也回来看过很多次,今天做了一些修改。
---2017.12.19 22:03
/**
* 测试用接口
* @author ChenSS
* @2017年1月1日
*/
public interface BaseDao {
public long queryId() ;
public String queryName();
}
/**
* 测试用Dao
* @author ChenSS
* @2017年1月1日
*/
public class UserDao implements BaseDao{
public long queryId() {
System.out.println("queryId方法执行中");
System.out.println("故意制造一个算术异常");
return 2/0;
}
public String queryName() {
System.out.println("queryName方法执行中");
return "xiaoming";
}
}
主函数
/**
* 测试函数
*
* @author ChenSS
* @2017年1月1日
*/
public class Test {
public static void main(String[] args) {
ProxyFactory factory = new ProxyFactory();
// 把我们写的四种代理全部放进去
factory.addAdvice(new MyMethodInterceptor());
factory.addAdvice(new MyMethodBeforeAdvice());
factory.addAdvice(new MyAfterReturningAdvice());
factory.addAdvice(new MyThrowsAdvice());
// 引介增强比较特殊,需要提供接口
factory.addAdvice(new MyIntroductionInterceptor());
factory.setInterfaces(BaseDao.class.getInterfaces());
// 需要代理的那个类
factory.setTarget(new UserDao());
try {
UserDao dao = (UserDao) factory.getProxy();
System.out.println(dao.queryName());
System.out.println();
System.out.println(dao.queryId());
} catch (Exception e) {
// TODO: handle exception
}
}
}
测试结果如下:
发现研究框架花了太多时间了,原计划年前将Spring框架写清楚,但是发现内容真的好多啊,暂时也只能写到这了,之后我得回归安卓了,做一些安卓的研究,这些天有点荒废安卓了。
各位新年快乐哈,不过文章发表似乎已经1月2号了,O(∩_∩)O哈哈~
Spring框架——AOP代理的更多相关文章
- spring框架 AOP核心详解
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子. 一 AOP的基本概念 (1)Asp ...
- 跟着刚哥学习Spring框架--AOP(五)
AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善.OOP引入 ...
- spring框架aop用注解形式注入Aspect切面无效的问题解决
由于到最后我的项目还是有个邪门的错没解决,所以先把文章大概内容告知: 1.spring框架aop注解扫描默认是关闭的,得手动开启. 2.关于Con't call commit when autocom ...
- Spring框架_代理模式(静态代理,动态代理,cglib代理)
共性问题: 1. 服务器启动报错,什么原因? * jar包缺少.jar包冲突 1) 先检查项目中是否缺少jar包引用 2) 服务器: 检查jar包有没有发布到服务器下: ...
- Spring框架-AOP详细学习[转载]
参考博客:https://blog.csdn.net/qq_22583741/article/details/79589910#4-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85% ...
- Spring框架 AOP面向切面编程(转)
一.前言 在以前的项目中,很少去关注spring aop的具体实现与理论,只是简单了解了一下什么是aop具体怎么用,看到了一篇博文写得还不错,就转载来学习一下,博文地址:http://www.cnbl ...
- 10 Spring框架 AOP (三) Spring对AspectJ的整合
上两节我们讲了Spring对AOP的实现,但是在我们的开发中我们不太使用Spring自身的对AOP的实现,而是使用AspectJ,AspectJ是一个面向切面的框架,它扩展了Java语言.Aspect ...
- Spring框架AOP学习总结(下)
目录 1. AOP 的概述 2. Spring 基于AspectJ 进行 AOP 的开发入门(XML 的方式): 3.Spring 基于AspectJ 进行 AOP 的开发入门(注解的方式): 4.S ...
- 记一次Spring的aop代理Mybatis的DAO所遇到的问题
由来 项目中需要实现某个订单的状态改变后然后推送给第三方的功能,由于更改状态的项目和推送的项目不是同一个项目,所以为了不改变原项目的代码,我们考虑用spring的aop来实现. 项目用的是spring ...
随机推荐
- OpenWRT UCI命令实现无线中继
本文主要功能主要是利用OpenWRT系统uci命令实现无线中继,主要是利用uci程序修改/etc/congfig/目录下的配置文件.实现步骤如下主要分为以下几步: 1) 安装 relayd (opkg ...
- 转:C++学习之Pair
Pair类型概述 pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同,基本的定义如下: pair<int, string> a; 表示a中有两个类型,第一个元素是int型的 ...
- 修改Oracle【12C】字符集
select userenv('language') from dual; //查看系统字符集编码 select * from nls_database_parameters where parame ...
- HiveQL简单操作DDL
hive-2.1.1 DDL操作 Create/Drop/Alter/Use Database 创建数据库 //官方指导 CREATE (DATABASE|SCHEMA) [IF NOT EXISTS ...
- C 返回函数与闭包的考虑
#include <stdio.h> typedef int (*fun)(); fun closure(int i) { int squ() { return i*i; } return ...
- 基于容器微服务的PaaS云平台设计(二)通过kubernetes实现微服务容器管理
版权声明:本文为博主原创文章,欢迎转载,转载请注明作者.原文超链接 ,博主地址:http://www.cnblogs.com/SuperXJ/ 上一章描述了基于spring cloud的微服务实例(实 ...
- 仿微信抢红包(js 转)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 《mysql必知必会》读书笔记--存储过程的使用
以前对mysql的认识与应用只是停留在增删改查的阶段,最近正好在学习mysql相关内容,看了一本书叫做<MySQL必知必会>,看了之后对MySQL的高级用法有了一定的了解.以下内容只当读书 ...
- 【机器学习实战】第12章 使用FP-growth算法来高效发现频繁项集
第12章 使用FP-growth算法来高效发现频繁项集 前言 在 第11章 时我们已经介绍了用 Apriori 算法发现 频繁项集 与 关联规则.本章将继续关注发现 频繁项集 这一任务,并使用 FP- ...
- Python迭代
本篇将介绍Python的迭代,更多内容请参考:Python学习指南 简介 在Python中,如果给定一个list或者tuple,我们可以通过for循环来遍历这个list或者tuple,这种遍历我们称为 ...