- 切面(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)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
三、Example:
1.导入支持包spring.jar和aspectjweaver.jar
2.编写类测试:
package org.ymm.dao;
/**
*接口LoginDao
*/
public interface ILoginDao {
public void login();
public void login(String uname);
public void login(String uname,String password);
}
package org.ymm.dao.impl;
import org.ymm.dao.ILoginDao;
/**
*接口ILoginDao的实现
*/
public class LoginDaoImpl implements ILoginDao {
@Override
public void login() {
// TODO Auto-generated method stub
System.out.println("login+++");
}
@Override
public void login(String uname) {
// TODO Auto-generated method stub
System.out.println(uname+"登陆了");
}
@Override
public void login(String uname, String password) {
// TODO Auto-generated method stub
System.out.println(uname+" "+password);
Integer num=Integer.parseInt(password);//报错拦截
}
}
package org.ymm.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 切面类MyAspect
* @author ymm
*/
//@Aspect
public class MyAspect {
//@Before("execution(* org.ymm.dao.impl.*.Login(..))")
public void before(JoinPoint j){
System.out.println(j.getClass());
System.out.println("before+++++++++");
}
public void after(){
System.out.println("after+++++++++");
}
//环绕切
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("doAround+++++++++");
long t=System.currentTimeMillis();
Object o= pjp.proceed();//需要手动调用被切得方法
t=System.currentTimeMillis()-t;
System.out.println("运行login(String)方法花了:"+t+"秒");
return o;
}
public void throwing(JoinPoint j,Object ex){
System.out.println(ex);
System.out.println("throwing+++++++++");
System.out.println(".....");
}
}
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 注解aop
<aop:aspectj-autoproxy/>
<bean id="L_ui" class="org.ymm.dao.impl.LoginDaoImpl"></bean>
<bean id="my_a" class="org.ymm.aop.MyAspect"></bean>
-->
<bean id="L_ui" class="org.ymm.dao.impl.LoginDaoImpl"></bean>
<bean id="my_aspect" class="org.ymm.aop.MyAspect"></bean>
<!-- 必须让spring来管理(Aspect)切面类 -->
<aop:config >
<aop:pointcut expression="execution(* org.ymm.dao.impl.LoginDaoImpl.login())" id="lg"/>
<aop:pointcut expression="execution(* org.ymm.dao.impl.LoginDaoImpl.login(String,String,..))" id="lg1"/>
<aop:aspect id="my_as" ref="my_aspect">
<aop:before method="before" pointcut-ref="lg"/>
<aop:after-returning method="after" pointcut="execution(* org.ymm.dao.impl.LoginDaoImpl.*())"/>
<aop:around method="doAround" pointcut="execution(* org.ymm.dao.impl.LoginDaoImpl.login(String))"/>
<aop:after-throwing throwing="ex" method="throwing" pointcut-ref="lg1" />
</aop:aspect>
</aop:config>
</beans>
package org.ymm.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.ymm.dao.ILoginDao;
/**
* 测试类
*/
public class Tester {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("beans.xml");
ILoginDao lld= ac.getBean("L_ui",ILoginDao.class);
//lld.login();//调用无参的 执行MyAspect切面的after()和before()
//lld.login("xxx");//执行MyAspect切面的doAround
try{
lld.login("a","x1");
}catch (Exception e) {
System.out.println("抓取未知错误...");
}
}
}