Spring AOP多种实现方式
1、四种方式实现
(1)基于XML配置实现AOP,
(2)基于自动代理器实现AOP,
(3)基于AspectJ注解实现
(4)基于AspectJ使用XML配置实现
2、所需jar包准备
至少需要准备下面四个jar包文件
3、几种方式实现AOP代理
首先新建几个类,栗子都是基于下面类
PersonService接口类
public interface PersonService {
public String eat();
public String work();
public String sleep();
public String dowrong();
}
PersonServiceImpl实现类
public class PersonServiceImpl implements PersonService {
@Override
public String eat() {
System.out.println("要吃饭了");
return null;
}
@Override
public String work() {
System.out.println("努力工作才有饭吃");
return "No pain no gain .";
}
@Override
public String sleep() {
System.out.println("休息好,养足精神!");
return "good night !";
}
@Override
public String dowrong() {
System.out.println("异常方法"+ 3/0);
return null;
}
}
新建切面类,分别实现相应接口,注意异常通知特殊点
/**
* 前置通知
* @author Administrator
*
*/
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("前置通知====实现梦想");
}
}
/**
* 后置通知
* @author Administrator
*
*/
public class MyMethodAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("后置通知====时间都去哪了");
}
}
/**
* 后置通知
* @author Administrator
*
*/
public class MyMethodAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("环绕通知====执行前处理");
Object result = invocation.proceed();
result = StringUtils.upperCase((String)result);
System.out.println("环绕通知====执行后处理");
return result;
}
}
/**
* 后置通知
* @author Administrator
*
*/
public class MyThrowsAdvice implements ThrowsAdvice {
//默认四个重载的afterThrowing方法,当目标方法抛出异常时执行
public void afterThrowing(Exception ex){
System.out.println("执行异常通知");
}
public void afterThrowing(UserException ex){
System.out.println("执行用户自定义异常"+ex.getMessage());
}
}
然后来看看XML配置
<!-- 注册目标对象 -->
<bean name="personService" class="aop.springaop.test5.PersonServiceImpl"/>
<!-- 注册切面通知 -->
<bean name="beforeAdvice" class="aop.springaop.test5.MyMethodBeforeAdvice"/>
<bean name="afterAdvice" class="aop.springaop.test5.MyMethodAfterAdvice"/>
<bean name="serviceproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--targetName与target二者均可 -->
<property name="targetName" value="personService"></property>
<!-- <property name="target" ref="personService"></property> -->
<!-- 方式一 使用字符串数组定义多个通知-->
<property name="interceptorNames" value="beforeAdvice,afterAdvice"></property>
<!-- 方式二 使用array定义多个通知 -->
<!-- <property name="interceptorNames">
<array>
<value>beforeAdvice</value>
<value>afterAdvice</value>
</array>
</property> -->
</bean>
测试方法
public static void main(String[] args) {
String resouce = "aop/springaop/test5/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
PersonService workService = (PersonService) applicationContext.getBean("serviceproxy");
workService.eat();
System.out.println("=====分割线=====");
workService.work();
System.out.println("=====分割线=====");
workService.sleep();
}
运行结果
(2)基于自动代理器实现AOP
常用的自动代理器有两种:DefaultAdvisorAutoProxyCreator 和 BeanNameAutoProxyCreator
<!-- 多个目标对象 -->
<bean name="personService" class="aop.springaop.test10.PersonServiceImpl"/>
<bean name="personService2" class="aop.springaop.test10.PersonServiceImpl"/>
<!-- 注册切面通知 -->
<bean name="beforeAdvice" class="aop.springaop.test10.MyMethodBeforeAdvice"/>
<!-- 注册切面顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"></property>
<property name="mappedName" value="work"></property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
第二种用BeanNameAutoProxyCreator 相对前者有更多优点,可以更加精细 <!-- 多个目标对象 -->
<bean name="personService" class="aop.springaop.test11.PersonServiceImpl"/>
<bean name="personService2" class="aop.springaop.test11.PersonServiceImpl"/>
<!-- 注册切面通知 -->
<bean name="beforeAdvice" class="aop.springaop.test11.MyMethodBeforeAdvice"/>
<!-- 注册切面顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"></property>
<property name="mappedName" value="work"></property>
</bean>
<bean id="myAdvisor2" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdvice"></property>
<property name="mappedName" value="sleep"></property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="personService"></property>
<property name="interceptorNames" value="myAdvisor"></property>
</bean>
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("前置通知====实现梦想");
}
}
public static void main(String[] args) {
String resouce = "aop/springaop/test10/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
PersonService workService = (PersonService) applicationContext.getBean("personService");
System.out.println("-----目标对象1---------");
workService.eat();
System.out.println("=====分割线=====");
workService.work();
System.out.println("=====分割线=====");
workService.sleep();
System.out.println("-----目标对象2---------");
PersonService workService2 = (PersonService) applicationContext.getBean("personService2");
workService2.eat();
System.out.println("=====分割线=====");
workService2.work();
System.out.println("=====分割线=====");
workService2.sleep();
}
前者结果,在切入点work()方法都进行增强了后者可以适用于Advisor 前者不可以,而且还可以指定到某个具体的目标对象方法
(3)基于AspectJ注解实现AOP
@Aspect //@Aspect注解表示当前类为切面
public class MyAspectJ {
@Before("execution(* *..eat(..) )")
public void before(){
System.out.println("AspectJ:====执行前置通知");
}
@AfterReturning(value="execution(* *..work(..))" ,returning="res")
public void afterReturning(Object res) {
res = res.toString().toUpperCase();
System.out.println("AspectJ:====执行后置通知 返回值:"+res);
}
@Around("execution(* *..PersonServiceImpl.sleep(..))")
public Object around(ProceedingJoinPoint procee) throws Throwable{
System.out.println("AspectJ:====执行环绕通知之前");
Object res = procee.proceed();
res = res.toString().toUpperCase();
System.out.println("AspectJ:====执行环绕通知之后"+res);
return res;
}
@After("execution(* *..PersonServiceImpl.eat(..))")
public void after(JoinPoint jp){
System.out.println("AspectJ:====执行最终通知"+jp);
}
@AfterThrowing(value="execution(* *..PersonServiceImpl.dowrong(..))",throwing="ex")
public void throwing(Exception ex){
System.out.println("AspectJ:====执行异常通知"+ex.getMessage());
}
}
配置文件,很简单
<bean id="myAspectJ" class="aop.aspectj.test1.MyAspectJ"></bean>
<bean id="personService" class="aop.aspectj.test1.PersonServiceImpl"/>
<!--启用注解-->
<aop:aspectj-autoproxy />
测试方法 public static void main(String[] args) {
String resouce = "aop/aspectj/test1/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
PersonService workService = (PersonService) applicationContext.getBean("personService");
System.out.println("-----目标对象1---------");
workService.eat();
System.out.println("=====分割线=====");
workService.work();
System.out.println("=====分割线=====");
workService.sleep();
}
测试结果public class MyAspectJ {
public void before(){
System.out.println("AspectJ:====执行前置通知");
}
public void before(JoinPoint jp){
System.out.println("AspectJ:====执行前置通知"+jp);
}
public void afterReturning(Object res) {
res = res.toString().toUpperCase();
System.out.println("AspectJ:====执行后置通知 返回值:"+res);
}
public Object around(ProceedingJoinPoint procee) throws Throwable{
System.out.println("AspectJ:====执行环绕通知之前");
Object res = procee.proceed();
res = res.toString().toUpperCase();
System.out.println("AspectJ:====执行环绕通知之后"+res);
return res;
}
public void after(JoinPoint jp){
System.out.println("AspectJ:====执行最终通知"+jp);
}
public void throwing(Exception ex){
System.out.println("AspectJ:====执行异常通知"+ex.getMessage());
}
}
XML配置文件 <bean id="myAspectJ" class="aop.aspectj.test3.MyAspectJ"></bean>
<bean id="personService" class="aop.aspectj.test3.PersonServiceImpl"/>
<!-- -->
<aop:config>
<!-- 定义切入点 -->
<aop:pointcut expression="execution(* *..eat(..) )" id="pointCutEat"/>
<aop:pointcut expression="execution(* *..work(..) )" id="pointCutWork"/>
<aop:pointcut expression="execution(* *..sleep(..) )" id="pointCutSleep"/>
<aop:pointcut expression="execution(* *..dowrong(..) )" id="pointCutDowrong"/>
<aop:aspect ref="myAspectJ">
<aop:before method="before" pointcut-ref="pointCutEat"/>
<aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="pointCutEat"/>
<aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="pointCutWork" returning="res"/>
<aop:around method="around(org.aspectj.lang.ProceedingJoinPoint)" pointcut-ref="pointCutSleep"/>
<aop:after method="after" pointcut-ref="pointCutEat"/>
<aop:after-throwing method="throwing(java.lang.Exception)" pointcut-ref="pointCutDowrong" throwing="ex"/>
</aop:aspect>
</aop:config>
测试方法 public static void main(String[] args) {
String resouce = "aop/aspectj/test3/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
PersonService workService = (PersonService) applicationContext.getBean("personService");
System.out.println("-----目标对象1---------");
workService.eat();
System.out.println("=====分割线=====");
workService.work();
System.out.println("=====分割线=====");
workService.sleep();
}
测试结果