1.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy />
<bean id="myAspect" class="com.yw.test08.AspectExample">
</bean>
<bean id="myclass" class="com.yw.test08.MyClass">
</bean>
</beans>
2.
package com.yw.test08;
public class MyClass
{
public void transfer()
{
System.out.println("transfer==");
}
public void test01()
{
System.out.println("test01====");
}
}
package com.yw.test08;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
//在启用@AspectJ支持的情况下,
//在application context中定义的任意带有一个@Aspect切面(拥有@Aspect注解)的bean
//都将被Spring自动识别并用于配置在Spring AOP
//切面(用 @Aspect 注解的类)和其他类一样有方法和字段定义。他们也可能包括切入点,通知和引入(inter-type)声明。
//声明一个切面
@Aspect
public class AspectExample
{
// Spring AOP 支持在切入点表达式中使用如下的AspectJ切入点指定者
// execution - 匹配方法执行的连接点,这是你将会用到的Spring的最主要的切入点指定者。
// within - 限定匹配特定类型的连接点(在使用Spring AOP的时候,在匹配的类型中定义的方法的执行)。
// this - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中bean reference(Spring AOP 代理)是指定类型的实例。
// target - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中目标对象(被代理的appolication object)是指定类型的实例。
// args - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中参数是指定类型的实例。
// @target - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中执行的对象的类已经有指定类型的注解。
// @args - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中实际传入参数的运行时类型有指定类型的注解。
// @within - 限定匹配特定的连接点,其中连接点所在类型已指定注解(在使用Spring AOP的时候,所执行的方法所在类型已指定注解)。
// @annotation - 限定匹配特定的连接点(使用Spring AOP的时候方法的执行),其中连接点的主题有某种给定的注解。
// 定义了一个切入点'anyOldTransfer', 这个切入点将匹配任何名为 "test01()" 的方法的执行:
@Pointcut("execution(* test01(..))")
// the pointcut expression
public void anyOldTransfer()
{
}// the pointcut signature
@Before("anyOldTransfer()")
public void before1()
{
System.out.println("AOP===before1===");
}
@Before("execution(* com.yw.test08.*.*(..))")
public void before2()
{
System.out.println("AOP===before2===");
}
@After("anyOldTransfer()")
public void after()
{
System.out.println("AOP===after===");
}
}
package com.yw.test08;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test
{
public static void main(String[] args)
{
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:com/yw/test08/applicationContext.xml");
// @AspectJ支持
MyClass o = (MyClass) app.getBean("myclass");
o.transfer();
o.test01();
}
}
3.运行如图
AOP概念官方说明:
Spring使用自己的术语。
-
切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以
@Aspect
注解(@AspectJ
风格)来实现。 -
连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点总是 代表一个方法的执行。 通过声明一个
org.aspectj.lang.JoinPoint
类型的参数可以使通知(Advice)的主体部分获得连接点信息。 -
通知(Advice): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。
-
切入点(Pointcut): 匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
-
引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可以使用一个引入来使bean实现
IsModified
接口,以便简化缓存机制。 -
目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied) 对象。
-
AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。
-
织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。
通知的类型:
-
前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
-
返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
-
抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。
-
后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
-
环绕通知(Around Advice): 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。
跟AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽量简单的通知类型来实现需要的功能。 例如,如果你只是需要用一个方法的返回值来更新缓存,虽然使用环绕通知也能完成同样的事情, 但是你最好使用After returning通知而不是环绕通知。 用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。 比如,你不需要调用JoinPoint
(用于Around Advice)的proceed()
方法,就不会有调用的问题。
在Spring 2.0中,所有的通知参数都是静态类型,因此你可以使用合适的类型(例如一个方法执行后的返回值类型)作为通知的参数而不是使用一个对象数组。
切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。