AspectJ是1个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面,所以可使用xml方式和注解方式来开发AOP
新版本Spring框架,建议使用AspectJ方式来开发AOP
aspectj有5种通知
before( Formals )
前置通知(在方法履行前履行,如果通知抛出异常,禁止方法运行)
after( Formals ) returning [ ( Formal ) ]
后置通知(方法正常返回后履行,如果方法中抛出异常,通知没法履行
必须在方法履行后才履行,所以可以取得方法的返回值。)
after( Formals ) throwing [ ( Formal ) ]
异常停止(方法抛出异常后履行,如果方法没有抛出异常,没法履行)
after( Formals )
终究通知(方法履行终了后履行,不管方法中是不是出现异常,类似try-catch-finally里面的finally块)
around( Formals )
环绕通知( 方法履行前后分别履行,可以禁止方法的履行,必须手动履行目标方法)
在xml中对应:
导入的jar包:
1.aop同盟规范
2.spring aop实现
3.aspect规范
4.spring aspect实现
编写进程:
1.目标类:实现+接口
2.切面类:编写多个通知
3.aop编程,将通知利用到目标类
4.测试
目标类:
接口
public interface UserService {
public boolean addUser();
public void updateUser();
public void deleteUser();
}
实现
public class UserServiceImpl implements UserService {
@Override
public boolean addUser() {
System.out.println("UserServiceDaoImpl addUser");
return true;
}
@Override
public void updateUser() {
//测试抛出异常通知
// int i=1/0;
System.out.println("UserServiceDaoImpl updateUser");
}
@Override
public void deleteUser() {
System.out.println("UserServiceDaoImpl deleteUser");
}
}
切面类
5种通知对方法的方法名称没有限制,但是方法的格式有限制。方法的格式会在xml配置中给出。
public class MyAspect {
//前置通知
public void before(JoinPoint joinPoint){
System.out.println("MyAspect-before");
}
//终究通知
public void after(JoinPoint joinPoint){
System.out.println("MyAspect-after");
}
//环绕通知
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("MyAspect-around-前");
Object obj=joinPoint.proceed();//履行目标方法
System.out.println("MyAspect-around-后");
return obj;
}
//后置通知
public void afterReturning(JoinPoint joinPoint,Object ret){
System.out.println("MyAspect-afterReturning "+joinPoint.getSignature().getName()+"\t"+ret);
}
//异常通知
public void afterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("MyAspect-afterThrowing "+e.getMessage());
}
}
spring配置
<?xml version="1.0" encoding="UTF⑻"?>
<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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 创建目标类 -->
<bean id="userServiceId" class="com.scx.xmlproxy.test.UserServiceImpl"></bean>
<!-- 创建切面类(通知) -->
<bean id="myAspectId" class="com.scx.xmlproxy.test.MyAspect"></bean>
<!-- aop编程-->
<aop:config proxy-target-class="true">
<aop:aspect ref="myAspectId">
<aop:pointcut expression="execution(* com.scx.xmlproxy.test.*.*(..))" id="myPointCut"/>
<!-- 前置通知
<aop:before method="before" pointcut-ref="myPointCut"/>
方法格式(参数1)
参数1:连接点描写
method:方法名
pointcut:切入点表达式
pointcut-ref:切入点援用
-->
<!-- 终究通知
<aop:after method="after" pointcut-ref="myPointCut"/>
方法格式(参数1)
参数1:连接点描写
-->
<!-- 环绕通知
<aop:around method="around" pointcut-ref="myPointCut"/>
方法格式(参数1)
参数:org.aspectj.lang.ProceedingJoinPoint
-->
<!-- 后置通知
<aop:after-returning method="afterReturning" returning="ret" pointcut-ref="myPointCut"/>
方法格式(参数1,参数2)
参数1:连接点描写
参数2:类型Object,参数名 returning="ret" 配置的
-->
<!--
抛出异常
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut" throwing="e"/>
方法格式(参数1,参数2)
参数1:连接点描写对象
参数2:取得异常信息,类型Throwable ,参数名由throwing="e" 配置
-->
</aop:aspect>
</aop:config>
</beans>
测试:
测试时,最好只履行1个通知,否则结果会和想象的不1样orz.
@org.junit.Test
public void testProxy(){
String xmlPath="com/scx/xmlproxy/test/applicationContext.xml";
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
UserService userService=(UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
测试结果:
前置通知:
后置通知:
异常通知:
为了出现异常我在实现类的updateUser方法里面里面添加了int i = 1 /0;
这行代码
结果如图所示输出了除0的异常
这时候候我们修改成终究通知。运行结果:
我们发现updateUser方法没有由于异常输出,但是终究通知输出了。
环绕通知:
注解小例子在写篇文章给出~