如何理解spring中的切面和过滤

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何理解spring中的切面和过滤相关的知识,希望对你有一定的参考价值。

1, 什么是AOP ?
面向方面/切面的编程:将程序中的交叉业务逻辑(公用代码)提取出来,称为切面,
将这些切面动态的织入到目标对象,生成一个新的代理对象的过程;
把程序划分为两部分:
1) 通用的交叉业务,公用的代码(日志,事务,安全);
2) 具体的业务逻辑处理代码;
将切面动态的织入到业务代码中;

面向方面/切面编程:将业务分解成切面与具体的业务逻辑模块,将切面透明的接入到业务逻辑模块中,形成一个完整的程序。比如:字符编码;日志;事务等等

2, AOP中的基本概念:
1)切面(Aspect): 指交叉业务逻辑的统称, 比如日志,事务,安全;
2)通知(Advice): 指切面的具体实现;
3)连接点(Joinpoint):指切面可以织入到(应用到)目标对象的位置(级别), 两个: 方法/属性
代理模式, 调用的是代理对象, 代理维护一个目标对象的属性;
调用方法之前, 先写日志; 再调用具体的实现方法;
调用属性之前, 拦截一下做处理,很少用;Spring目前不支持这个;
4)切入点(Pointcut):指通知(切面的具体实现)应用到哪些目标对象的哪些方法或者哪些属性上;
org.springframework.aop.Pointcut
Spring根据类名称及方法名称定义Pointcut,表示Advice织入至应用程序的时机;
5)引入(introduction):指动态的给一个对象增加方法或者属性的过程;是一种特殊的通知;
6)织入(weaving):将切面(通知)应用到目标对象生成代理的过程;
7)代理对象(Proxy): 目标对象应用切面以后生成的代理(切面织入之后生成的新的代理对象);
8)目标对象(Target): 具体业务逻辑的实现(需要织入切面的对象);

3, Spring的AOP, 使用的是动态代理;
1) 代理的两种方式:
静态代理:
针对每个具体类分别编写代理类;
针对一个接口编写一个代理类;
IRegister
RegisterService <--- RegisterProxy
目标对象 代理对象
IRegister ir; 调用代理的方法, 代理再去调用目标对象的方法;

IReport
ReportService <--- ReportProxy
目标对象 代理对象
每一个代理对象只为一个目标对象服务;

动态代理:
针对一个方面编写一个InvocationHandler,
然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类

告诉一个类,我的接口是什么, 目标类是什么, 自动生成代理;
2) 动态代理例子:
public class MyProxyCreater implements java.lang.reflect.InvocationHandler
private Object target;

public MyProxyCreater(Object target)
super();
this.target = target;

public static Object createProxy(Object o)
//类加载器,实现的接口,代理生成的类
//根据三个参数创建一个代理对象;
//通过类加载器,借口,和实现类得到一个代理对象
//目标对象最少要实现一个接口
return
Proxy.newProxyInstance(o.getClass().getClassLoader(),
o.getClass().getInterfaces(),new MyProxyCreater(o));

//代理对象,目标方法,目标对象的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
Object rst=null;
//加切面
System.out.println("loging...");
rst=method.invoke(target, args);
return rst;



spring思想:
1,将切面使用动态代理的方式动态地织入到目标对象(被代理对象)生成新的代理对象;
2,目标对象如果没有实现代理接口,spring采用CGLIB来生成代理对象,
该代理对象是目标对象的子类;
3,目标对象如果是final类,并且没有实现代理接口,就不能运用AOP了;

目标对象如果没有实现接口, spring采用CGLIB库来动态生成一个代理,
代理是目标对象的子类; 目标对象不能是final的;
Spring采用动态代理来实现AOP, 在运行时,spring将切面应用到目标对象生成动态代理,
客户端使用动态代理来调用;
AspectJ: 需要学习一些别的语言,
支持属性连接点; 可以在编译期生成代理; 需要把编译器重新写一遍;
难度比较大;

3) Advice :
切面的实现:
类型:
(1)org.springframework.aop.MethodBeforeAdvice
在方法调用之前,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
before(目标方法,目标方法的参数,目标对象);
public void before(Method method, Object[] objectArray, Object object) throws Throwable
(2)org.springframework.aop.AfterReturningAdvice
在方法调用之后,做处理。
不能够改变返回值
不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)
void afterReturning(Object returnValue, Method method, Object[] args, Object target)
(3)org.aopalliance.intercept.MethodInterceptor
aop联盟框架; 保证代码兼容别的aop框架;
拦截器, 通知,跟filter差不多;
在方法调用之前以及之后,做处理。
可以改变返回值,也可以改变流程。
public Object invoke(MethodInvocation methodInvocation) throws Throwable
(4)org.springframework.aop.ThrowsAdvice
在目标方法抛出异常后,会根据异常类型选择的做处理。
当该通知处理完异常后,会简单地将异常再次抛出给客户端调用。
public void afterThrowing(IllNameException e);
public void afterThrowing(IllAgeException e);

内置的创建代理类:
org.springframework.aop.framework.ProxyFactoryBean
proxyInterfaces,interceptorNames,target
作用:依照配置信息,将切面应用到目标对象,生成动态代理对象;

配置过程:
(1)配置目标对象,
(2)注入切面: 通知, Advisor, 拦截器
(3)利用ProxyFactoryBean将切面织入到目标对象,生成动态代理对象;
客户端调用的是代理的对象;
如果目标对象没有实现指定接口,不用配置ProxyInterfaces, (cglib会生成一个);
实现了接口,也可以不写的;
(4)客户端使用动态代理来访问目标对象的方法。

注: 在默认情况下,通知会应用到目标对象的所有方法之上。
编码过程: 目标对象--通知--代理--客户端调用;

例子: (aop3)四种通知 ;
<bean id="registerServiceTarget" class="aop3.RegisterServiceImpl"/>
<bean id="logingAdvice" class="aop3.LogingAdvice"/>
<bean id="welcomeAdvice" class="aop3.WelcomeAdvice"/>
<bean id="registerInterceptor" class="aop3.RegisterInterceptor"/>
<bean id="registerThrowingAdvice" class="aop3.RegisterThrowingAdvice"/>

<bean id="registerService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><!-- 目标对象实现的接口 -->
<value>aop3.IRegisterService</value>
</property>

<property name="target"><!-- 配置(指定)目标对象 -->
<ref bean="registerServiceTarget"/>
</property>

<property name="interceptorNames"><!-- 需要织入到目标对象的切面(通知,advisor,拦截器) -->
<list>
<value>logingAdvice</value>
<!--
<value>welcomeAdvice</value>

<value>registerInterceptor</value>

<value>registerThrowingAdvice</value>
-->
</list>
</property>
</bean>

练习: (aop4)在拦截器设置一个属性,记录方法超时的时间;

4) 切入点:
通知具体应用到哪些类的哪些方法之上;
自定义切入点:用来约束Advice
步骤:
1)实现org.springframework.aop.ClassFilter--->用来过滤类(哪些类可以应用切面)
如果返回值为true时, 则应用切面; 否则不应用切面;
对类进行过滤,看要不要将切面应用到该类上;

2)实现org.springframework.aop.MethodMatcher--->用来过滤方法(类中的哪些方法应用切面)
方法1: boolean matches(Method, Class);//
方法2: boolean isRunTime(); 返回值为真,该切入点是动态切入点;
否则是静态切入点; 方法3不会被执行;
方法3: boolean matches(Method, Class,Object[]);//这个方法可以动态的获得方法的信息;

解释:
静态切入点:
在目标方法被执行以前, 确定切面是否应用到目标方法之上;
根据目标方法的静态特征(方法所在的类名A, 方法名f1), 来决定;
一般用这个;
动态切入点:
在目标方法每一次执行,会依照方法的动态的特征来决定是否应用切面;
动态特征: 当前方法的参数值, 等等;
会影响性能很大, 很少使用;

3)实现org.springframework.aop.Pointcut

4)实现org.springframework.aop.PointcutAdvisor:将Pointcut与Advice结合到一起。
是一个特殊的通知,它包含了切入点在内;
注意:
在此可定义两个属性,并且通过配置文件来完成装配工作;
private Advice advice;//通知的实现;
private Pointcut pointcut;//通知的应用地点;
在配置文件中,将自定义的切入点与通知绑订到一起,成为Advisor;

5)利用ProxyFactoryBean将advisor织入到目标对象
参考技术A 切面这个我的理解就是:以前开发都是从前台到service层再到domain层,spring中的切面就不再是一条线的开发方式,而是面向一个层,比如在配置事务的时候配置到service层,这就是切面的一个应用。过滤就是把提交的东西和展示到前台的东西筛选一遍,例如写一个编码的过滤器,在从前台想后台提交东西的时候,在到action之前,spring会把编码设置成你想设置的编码格式。本回答被提问者采纳

以上是关于如何理解spring中的切面和过滤的主要内容,如果未能解决你的问题,请参考以下文章

理解Spring中的IOC和AOP

5 分钟理解 Spring 中的 AOP

Spring 中的Aop 的理解

(十六)ATP应用测试平台——java应用中的过滤器Filter拦截器Interceptor参数解析器ResolverAop切面,你会了吗?

Spring中的AOP概念

深入理解AOP-代理的秘密