Spring之AOP二
在Spring之AOP一中使用动态代理将日志打印功能注入到目标对象中,其实这就是AOP实现的原理,不过上面只是Java的实现方式。AOP不管什么语言它的几个主要概念还是有必要了解一下的。
一、AOP概念
1.横切关注点
AOP把一个业务流程分成几部分,例如权限检查、业务处理、日志记录,每个部分单独处理,然后把它们组装成完整的业务流,每部分被称为切面或关注点。
2.切面
类是对物体特征的抽象,切面就是对横切关注点的抽象。可以每部分抽象成一叠纸一样一层一层的,那每张纸都是一切面。
3.连接点
被拦截到的点,我看有的博客说:因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器.其实我觉得Spring只支持方法类型的连接点就包含字段和构造器。为啥呢?因为字段它是通过get,set方法,构造器它其实也是方法。Spring只支持方法类型的连接点和连接点是字段或者构造器它们是包含关系。
4.切入点
对连接点进行拦截的定义,连接点可以很多,但并不一定每个连接点都进行操作,比如莲藕,藕段与藕段之间它们是有连接点的,但不一定都切开。
5.通知
通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类,这个呢就是把藕段与藕段断开之后要做的事情,是往里面加蜂蜜还是做什么。
6.目标对象
代理的目标对象,就是上一博客动态代理的target,在实际操作中一般会先实现AOP的接口,然后配置这些接口作用到哪些对象上,被作用的对象就是目标对象。
7.织入
切面是独立的,目标对象也是独立的,它们是不耦合的,那它怎么把切面放到目标对象中呢,这时就需要进行织入操作,就类似一中的,怎么把target和打印日志联系到一起呢,那就需要动态代理,在spring中aop.framework.ProxyFactory就是用作织入器,来进行横切逻辑的织入。
8.引入
不改代码的同时,为类动态的添加方法或字段。
二、AOP配置
| AOP配置元素 | 描述 |
|---|---|
<aop:config> |
顶层的AOP配置元素,大多数的<aop:*>元素必须包含在<aop:config>元素内 |
<aop:aspect> |
定义切面 |
<aop:aspect-autoproxy> |
启用@AspectJ注解驱动的切面 |
<aop:pointcut> |
定义切点 |
<aop:advisor> |
定义AOP通知器 |
<aop:before> |
定义AOP前置通知 |
<aop:after> |
定义AOP后置通知(不管被通知的方法是否执行成功) |
<aop:after-returning> |
定义成功返回后的通知 |
<aop:after-throwing> |
定义抛出异常后的通知 |
<aop:around> |
定义AOP环绕通知 |
<aop:declare-parents> |
为被通知的对象引入额外的接口,并透明地实现 |
三、实现
1.pom.xml引入aspectjweaver.jar、aspectjrt.jar
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.5.4</version>
</dependency>
2.定义切面类
package Cuiyw.Spring.Service; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint; public class ServiceAspect {
public void beforeAdvice() {
System.out.println("前置通知执行了");
} public void afterAdvice() {
System.out.println("后置通知执行了");
} public void afterReturnAdvice(String result) {
System.out.println("返回通知执行了" + "运行业务方法返回的结果为" + result);
} public String aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
String result = "";
try {
System.out.println("环绕通知开始执行了");
long start = System.currentTimeMillis();
result = (String) proceedingJoinPoint.proceed();
long end = System.currentTimeMillis();
System.out.println("环绕通知执行结束了");
System.out.println("执行业务方法共计:" + (end - start) + "毫秒。");
} catch (Throwable e) { }
return result;
} public void throwingAdvice(JoinPoint joinPoint, Exception e) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("异常通知执行了.");
stringBuffer.append("方法:").append(joinPoint.getSignature().getName()).append("出现了异常.");
stringBuffer.append("异常信息为:").append(e.getMessage());
System.out.println(stringBuffer.toString());
} }
3.上下文中定义切面、切点
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<bean id="serviceImplA" class="Cuiyw.Spring.Service.ServiceImplA" />
<bean id="serviceAspectBean" class="Cuiyw.Spring.Service.ServiceAspect" />
<!-- 配置一个切面 -->
<aop:config>
<aop:aspect id="serviceAspect" ref="serviceAspectBean">
<aop:pointcut id="servicePointcut" expression="execution(* Cuiyw.Spring.Service.*.*(..))" />
<!-- 配置前置通知 -->
<aop:before pointcut-ref="servicePointcut" method="beforeAdvice" />
<!-- 配置前置通知 -->
<aop:after pointcut-ref="servicePointcut" method="afterAdvice" />
<!-- 配置后置返回通知 -->
<aop:after-returning pointcut-ref="servicePointcut" method="afterReturnAdvice" returning="result" />
<!-- 配置环绕通知 -->
<aop:around pointcut-ref="servicePointcut" method="aroundAdvice" />
<!-- 异常通知 -->
<aop:after-throwing pointcut-ref="servicePointcut" method="throwingAdvice" throwing="e" />
</aop:aspect>
</aop:config>
</beans>
4.在main中调用service
ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
BeanFactory factory=context;
IService serviceImplA1=(IService)factory.getBean("serviceImplA");
serviceImplA1.service("Cuiyw ServiceA");

5.错误
ServiceImplA serviceImplA2=factory.getBean("serviceImplA",ServiceImplA.class);
serviceImplA2.service("Cuiyw ServiceA");
使用上面的代码来测试出现下面的错误,使用4中接口的方式就可以,这个是参考http://blog.csdn.net/two_people/article/details/51816964中的
Bean named 'serviceImplA' is expected to be of type 'Cuiyw.Spring.Service.ServiceImplA' but was actually of type 'com.sun.proxy.$Proxy4'

四、总结
上面演示了AOP的实现方式,其实还有多种方式实现,这里只写了一个demo。还有3个小时就到2018了,祝大家新年快乐!
五、补充
最近在回头整理Spring相关方面的知识,在写demo的时候,按照上面的来重新配置居然报错了,之前是可以运行成功的,百度了好久也是没找到原因,后来想着重新写,参考网上了例子,更改了下aspectjweaver、aopalliance版本号居然可以了。
Spring之AOP二的更多相关文章
- Spring学习(二)——Spring中的AOP的初步理解[转]
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring. ...
- Spring自学教程-IOC、DI、AOP(二)
一.spring的IOC-就是怎样使用spring来创建对象 二.springDI(依赖注入)-就是怎样给属性赋值 通过set方式赋值 以下我们只需要记住两点的赋值,基本类型和引用类型的赋值 基本类型 ...
- spring学习总结二-----面向切面编程(AOP)思想
上一篇spring博客简总结了spring控制反转和依赖注入的相关思想知识点,这篇博文对spring的面向切的编程思想进行简单的梳理和总结. 一.面向切面的思想 与面向对象的纵向关系概念不同,面向切面 ...
- spring学习笔记二 注解及AOP
本节需要导入spring-aop包 注解 使用注解的目的是为了代替配置,在使用注解时,省略键时,则是为value赋值. 扫描某个包下的所有类中的注解 <?xml version="1. ...
- 代理模式及Spring AOP (二)
一.Spring AOP 1.1 Spring AOP 底层还是用的动态代理.如果目标对象所对应的类有接口,spring就用jdk生成代理对象: 如果目标对象所对应的类没有接口,spring就用C ...
- Spring入门(二)— IOC注解、Spring测试、AOP入门
一.Spring整合Servlet背后的细节 1. 为什么要在web.xml中配置listener <listener> <listener-class>org.springf ...
- Spring学习(二)——Spring中的AOP的初步理解
[前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...
- 09 Spring框架 AOP (二) 高级用法
上一篇文章我们主要讲了一点关于AOP编程,它的动态考虑程序的运行过程,和Spring中AOP的应用,前置通知,后置通知,环绕通知和异常通知,这些都是Spring中AOP最简单的用法,也是最常用的东西, ...
- Spring学习笔记(二)Spring基础AOP、IOC
Spring AOP 1. 代理模式 1.1. 静态代理 程序中经常需要为某些动作或事件作下记录,以便在事后检测或作为排错的依据,先看一个简单的例子: import java.util.logging ...
随机推荐
- JAVA 中LinkedHashMap要点记录
JAVA 中LinkedHashMap要点记录 构造函数中可能出现的几个参数说明如下: 1.initialCapacity 初始容量大小,使用无参构造方法时,此值默认是16 2.loadFactor ...
- Android APK反编译 apktool使用教程
2017年棋牌游戏突然就火了,正所谓春江水暖鸭先知本猿处在软件行业中就能清晰的感受到市场的变化,最近老家那边也是玩的风生水起,于是最近闲暇时光想到反编译下这些棋牌软件,看看代码实现的思路 (注:反编译 ...
- centos 使用 beyond compare 对比工具
我这里的环境是centos7桌面版 三条命令安装beyond compare wget http://www.scootersoftware.com/bcompare-4.2.3.22587.x86_ ...
- apache通过AD验证
## apache通过AD验证 #yum install httpd mod_authz_ldap#安装apahce的ldap模块yum install mod_authz_ldap -y #配置ap ...
- 五十个小技巧提高PHP执行效率(二)
更详细具体的总结如下: 1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量, 单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的 ...
- C#访问C++动态分配的数组指针
项目中遇到C#调用C++算法库的情况,C++内部运算结果返回矩形坐标数组(事先长度未知且不可预计),下面方法适用于访问C++内部分配的任何结构体类型数组.当时想当然的用ref array[]传递参数, ...
- UWP ListView下模板宽度问题
在ListView中模板的宽度默认不会根据listView的宽度改变为改变,这需要更改一下设置,重点在于设置HorizontalContentAlignment的拉伸模式.注意是HorizontalC ...
- 5、C#基础 - C#的值类型
1.C#的值类型 有几个特点: 存储在栈里 基于值类型的变量直接包含值(值类型存储实际值). 将一个值类型变量赋给另一个值类型变量时,将复制包含的值. 这与引用类型变量的赋值不同,引用类型变量的赋值只 ...
- 在学java继承中
看到一片个人认为的好博客,http://www.cnblogs.com/dolphin0520/p/3803432.html ;这一节看的比较慢,加油,就是干: 分类不好意思分到Java中,嘿嘿还 ...
- loadrunner 录制TCP协议脚本操作
测试TCP协议的项目,涉及到登陆.发送实时数据.指令.登出等,直接写报文工作量太大,所以需要录制报文. 操作方法如下: 1.启动服务端程序 2.使用winsocket协议 3.选择应用程序 4.录制选 ...