这里使用两种方式实现各类通知:
(1)采用@Aspect切面注解的方式
(2)采用xml配置的方式
一、准备工作:
需要依赖的maven jar包
<!--使用AspectJ方式注解需要相应的包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.0</version>
</dependency>
<!--使用AspectJ方式注解需要相应的包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!--spring上下文包,在加载spring配置文件时用到-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<!-- Spring aop包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6.RELEASE</version>
spring xml 需要加入aop 的命名空间和具体用到的schema资源 :
下面包含了aop的,直接采用就好
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
二、
1.第一种方式:
需要代理的类:
package com.aop;
import org.springframework.stereotype.Service;
/**
* 文件名称: com.aop.PersonServiceImpl.java</br>
* 初始作者: bk_yzw</br>
* 创建日期: 2017年11月25日</br>
*
*/
@Service
public class PersonServiceImpl implements PersonService {
private String userName = null;
public PersonServiceImpl() {
super();
}
public PersonServiceImpl(String userName) {
super();
this.userName = userName;
}
@Override
public String getUserName() {
return userName;
}
@Override
public boolean save(String userName, int age) {
System.out.println("这是一个保存方法" + userName);
// throw new RuntimeException("异常通知");
return true;
}
@Override
public boolean update(String userName, int age) {
System.out.println("这是一个修改方法,修改人:" + userName);
System.out.println("这是一个修改方法,修改人年龄:" + age);
// throw new RuntimeException("异常通知");
return true;
}
}
切面:
package com.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 文件名称: 该类定义</br>
* 初始作者: bk_yzw</br>
* 创建日期: 2017年11月25日</br>
*/
// 切面注解
@Aspect
public class AopAnnotation {
@Pointcut(value = "execution(* com.aop..*.*(..)) ")
public void advice() {
}// 申明切入点
// 前置通知
@Before(value = "advice() && args(name,age)", argNames = "name,age")
public void beforeAdvice(String name, int age) {
System.out.println("前置通知" + name);
}
// 返回通知
@AfterReturning(pointcut = "advice() ", returning = "a")
public void afterReturningAdvice(boolean a) {
System.out.println("返回通知" + a);
}
// 异常通知
@AfterThrowing(pointcut = "advice() ", throwing = "e")
public void afterThrowingAdvice(Exception e) {
System.out.println("异常通知" + e);
}
// 最终通知
@After("advice()")
public void afterAdvice() {
System.out.println("最终通知");
}
// 环绕通知
@Around("advice()")
public Object doAround(ProceedingJoinPoint point) {
Object obj = null;
try {
obj = point.proceed();
obj = false;
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
return obj;
}
}
}
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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 开启aop切面注解 -->
<aop:aspectj-autoproxy/>
<bean id="aopAnnotation" class="com.aop.AopAnnotation"> </bean>
<bean id="personService" class="com.aop.PersonServiceImpl"> </bean>
</beans>
测试:
package com.aop;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 文件名称: com.aop.AopTest.java</br>
* 初始作者: bk_yzw</br>
* 创建日期: 2017年11月25日</br>
*/
public class AopTest {
@Test
public void myTest() {
ClassPathXmlApplicationContext cont = new ClassPathXmlApplicationContext(
"classpath:spring/dispatcher-servlet.xml");
PersonService Person = (PersonService) cont.getBean("personService");
boolean falg = Person.update("张三", 18);
System.out.println(falg);
}
}
5种通知结果:
前置通知:
======》
前置通知张三
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
true
======》
返回通知:
=====》
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
返回通知true
true
=====》
异常通知:(注意需要抛异常)
====》
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
异常通知java.lang.RuntimeException: 异常通知
====》
最终通知:
====》
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
最终通知
true
====》
环绕通知:(注意这里方法返回值修改了由true变为falsel 了)
====》
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
false
====》
1.第二种方式:
(1)需要代理同上
(2)切面类,此类不需要任何注解,交给xml配置
package com.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 文件名称: com.aop.Advice.java</br>
* 初始作者: bk_yzw</br>
* 创建日期: 2017年11月27日</br>
*/
public class Advice {
// 前置通知
public void beforeAdvice(JoinPoint point) {
System.out.println("前置通知" + point.getArgs()[0]);
}
// 返回通知
public void afterReturningAdvice(boolean a) {
System.out.println("返回通知" + a);
}
// 异常通知
public void afterThrowingAdvice(Exception e) {
System.out.println("异常通知" + e);
}
// 最终通知
public void afterAdvice() {
System.out.println("最终通知");
}
// 环绕通知
public Object doAround(ProceedingJoinPoint point) {
Object obj = null;
try {
System.out.println("进入方法");
obj = point.proceed();
System.out.println("后退方法");
obj = false;
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
return obj;
}
}
}
(3)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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 开启aop切面注解 -->
<aop:aspectj-autoproxy/>
<!-- spring 扫描包 -->
<context:component-scan base-package="com.aop" />
<!-- <bean id="aopAnnotation" class="com.aop.AopAnnotation"> </bean> -->
<!-- <bean id="personService" class="com.aop.PersonServiceImpl"> </bean> -->
<bean id="advice" class="com.aop.Advice"> </bean>
<aop:config>
<aop:aspect id="myAspect" ref="advice">
<aop:pointcut expression="execution(* com.aop..*.*(..))" id="myput"/>
<aop:before method="beforeAdvice" pointcut-ref="myput" />
<aop:after-returning method="afterReturningAdvice" pointcut-ref="myput" returning="a"/>
<aop:after-throwing method="afterThrowingAdvice" pointcut-ref="myput" throwing="e"/>
<aop:after method="afterAdvice" pointcut-ref="myput"/>
<aop:around method="doAround" pointcut-ref="myput" />
</aop:aspect>
</aop:config>
</beans>
(4)测试
package com.aop;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 文件名称: com.aop.AopTest.java</br>
* 初始作者: bk_yzw</br>
* 创建日期: 2017年11月25日</br>
*/
public class AopTest {
@Test
public void myTest() {
ClassPathXmlApplicationContext cont = new ClassPathXmlApplicationContext(
"classpath:spring/dispatcher-servlet.xml");
PersonService Person = (PersonService) cont.getBean("personServiceImpl");
boolean falg = Person.update("张三", 18);
System.out.println(falg);
}
}
(5)结果:(此结果包含所有通知,注意返回值改了,在环绕通知中修改的)
====》
前置通知张三
进入方法
这是一个修改方法,修改人:张三
这是一个修改方法,修改人年龄:18
后退方法
最终通知
返回通知false
false
====》
总结:
1.方法传递的参数可以JoinPoint 类获得,个人感觉就不用再xml中写arg-names了,太局限了
2.在定义切面时,有规定哪些路径下有切面主要通过execution(* com.aop...(..)) 这个过滤
execution(* com.aop...(..):这个表达式意思时,返回值不限,在com.aop包下面所有子包中的所有类的所有方法,任何参数.
execution(* com.aop.service..(..)):这个同上,但是确定了com.aop.service包,只有这个包中类才可以。
execution(* com.aop.service.person.*(..)):这相对与上面控制到具体的类
execution(* com.aop.service.person.save(..)):具体到方法名
3.spring 还有增强性的通知,xml中则用<aop:advisor />
注解,这种方式制定了具体通知类型,该通知类型在对应的类中实现了,增强类可以在这个地方看看:http://blog.csdn.net/qq_32166627/article/details/72868339
http://blog.csdn.net/u011983531/article/details/70504281
例如:
<!-- 日志拦截器 -->
<bean id="loggerInterceptor" scope="singleton" class="com.sdusz.framework.core.log.LoggerInterceptor" />
<!-- 设置aop规则,应用日志拦截 -->
<aop:config>
<aop:advisor pointcut="execution(* com.olife.admin.service..*.*(..))" advice-ref="loggerInterceptor"/>
</aop:config>
经供参考…