Filter(过滤器)与Interceptor(拦截器)和Spring AOP的区别?

Filter过滤器:拦截web访问url地址。

Interceptor拦截器:拦截以 .action结尾的url,拦截Action的访问。

Spring AOP拦截器:只能拦截Spring管理Bean的访问(业务层Service)

AOP

AOP即面向切面编程,希望将分散在各个业务逻辑代码中的相同代码通过横向切割的方法抽取大一个独立的模块中,给业务逻辑类一个清新的世界.

AOP 术语

  • 连接点

一个类或者一段程序拥有一些具有边界性质的特定点,这些代码中的特定点就成为连接点,spring仅支持方法的连接点,即仅能在方法调用前,方法调用后,方法抛出异常时这些程序执行点织入增强.

  • 切点

每个程序类都有多个连接点,AOP通过切点来定位特定的连接点,类比数据库.连接点相当于数据库中的记录,而切点相当于查询条件,一个切点可以匹配多个连接点.

  • 增强

增强是织入目标连接点上的一段程序代码

  • 目标对象

增强逻辑的织入目标类

  • 引介

引介是一种特殊的增强,它为类增加一些属性和方法

  • 织入

织入是将增强添加到目标类的具体连接点上的过程

  • 代理

一个类被AOP织入增强后,就产生了一个结果类,它是融合了原类和增强逻辑的代理类.

  • 切面

切面由切点和增强组成,既包括横切逻辑的定义,也包括连接点的定义.

JDK动态代理

​ JDK的动态代理主要涉及java.lang.reflect包中的两个类,ProxyInvocationHandler,其中InvocationHandler是一个接口,可以通过该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切罗杰和业务逻辑编织在一起.

​ 而Proxy利用InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象.

spring对AOP的支持

springAOP包括了基于XML配置的AOP和基于@AspectJ注解的AOP,两种方法在配置切面时的表现方式不同,但是底层都采用了动态代理技术

了解注解

注解是代码的附属信息,遵循一个基本原则,注解不能直接干扰程序代码的运行,无论增加还是删除注解,代码都可以正常运行,Java语言解释器会忽略这些注解,而由第三方工具对注解进行处理,第三方工具可以利用代码中的注解间接控制程序代码的运行,他们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,

使用@AspectJ

使用前的准备: spring在处理@AspectJ注解表达式时,需要将spring的asm模块添加到类路径中,asm是轻量级的字节码处理框架,因为Java的反射机制无法获取入参名,spring就利用asm处理@AspectJ中所描述的方法入参名. spring采用AspectJ提供的@AspectJ注解类库及相应的解析类库,需要在pom.xml文件中添加aspectj.weaver和aspectj.tools类包的依赖.

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<!--使用AspectJ方式注解需要相应的包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>

一个例子

1
2
3
4
5
6
7
8
9
10
11
public class NativeWaiter implements Waiter
{
public void greetTo(String clientName)
{
System.out.println("greet"+clientName);
}
public void serveTo(String clientName)
{
System.out.println("serve"+clientName);
}
}

下面用@AspectJ定义一个切面

1
2
3
4
5
6
7
8
9
@Aspect // 通过该注解把PreGreetingAspect标识为一个切面
public class PreGreetingAspect
{
@Before("execution(* greeTo(..))") //定义切点以及增强类型
public void beforeGreeting() //增强的横切逻辑
{
System.out.println("How are you");
}
}

@before表示是前置增强,成员值是一个@AspectJ切点表达式,意思是在目标类的greetTo方法上织入增强,greetTo()方法可以带任意的入参和任意的返回值.最后,beforeGreeting是增强使用的横切逻辑,该横切逻辑在目标方法调用前调用.

配置AspectJ切面

使用基于schema的aop命名空间进行配置

切面类必须还要在spring中注册

@AspectJ语法基础

AspectJ切点表达式由关键字和操作参数组成,如切点表达式execution(* greeTo(..)) execution 为关键字,

* greeTo(..) 为操作参数,execution代表目标类执行某一方法,而 * greeTo(..)描述目标方法的匹配模式串,二者联合起来来表示目标类greetTo()方法的连接点.

切面表达式分成三种,第一种就是指示器,描述通过什么样方式匹配对应的类的方法

第二种就是通配符,第三种就是运算符,描述多个不同的匹配条件之间的逻辑

通配符
  • *匹配任意数量的字符
  • +匹配指定的类及其子类
  • ..匹配任意数的子包或参数
运算符
  • && and 运算符
  • || or运算符
  • ! 非运算符
designators 指示器

匹配方法: execution

匹配注解: @target @args @within @annotation

匹配包/类型: within()

匹配对象: this() bean() target()

匹配参数 args()

主要是execution匹配

语法如下:(模式指的是都可以用前面的通配符进行匹配)

1
execution(<修饰符模式(public等)>  <返回类型模式> <方法名模式>(<参数模式>) <异常模式>)
  • 通过方法签名定义切点
1
2
execution(public * *(..)) 匹配所有目标类的public方法,第一个*代表返回类型,第二个*代表方法名.
execution(* *To(..)) 匹配目标类中所有以To为后缀的方法
  • 通过类定义切点
1
2
execution(* com.sysu.Waiter.*(..)匹配com.sysu.Waiter接口中的所有方法,第一个*表示任意返回类型)
execution(* com.sysu.Waiter+.*(..)) 匹配waiter接口及其实现类的所有方法
  • 通过类包定义切点
1
2
3
execution(* com.sysu.* (..))匹配com.sysu包下所有类的所有方法
execution(* com.sysu..*(..))匹配com.sysu 包,子孙包下所有类的所有方法
execution(* com..*.*Dao.find*(..))匹配包前缀名为com的任何包下类名后缀为Dao的方法.方法名以find前缀
  • 通过方法入参定义切点
1
2
3
execution(* joke(String,int)) 匹配joke(String,int)方法
execution(* joke(String,* ))匹配joke方法,且第一个参数是String类型
execution(* joke(String,..)) 第二个参数可以有无限类型.