spring aop实战
本篇只是用实际案例帮助快速入门,不涉及具体概念
1.0 开发环境
1.0 开发工具 eclipse
2.0 jar包 除了Spring jar包外,还需要其他jar包 spring本身并没有提供 我也不知为什么
https://pan.baidu.com/s/16MTV5K8zG8m9cROC-6G_iQ 提取码:hro2
2.0 搭建主业务模块 Affairs.java
package com.ccut.aop;
import java.io.IOException;
public class Affairs {
private String message1;
private String message2;
public Affairs(){}
public String getMessage1() {
return message1;
}
public void setMessage1(String message1) {
this.message1 = message1;
}
public String getMessage2() {
return message2;
}
public void setMessage2(String message2) {
this.message2 = message2;
}
public void PersonA(){
System.out.println("A 这个人说啊:"+this.getMessage1());
}
public void PersonB(){
System.out.println("B 这个人说啊:"+this.getMessage2());
}
public void error(){
System.out.println("error!!!");
int i = 10;
if(i != 1){
throw new IllegalArgumentException("这是参数异常");
}
}
}
3.0 搭建切面功能类Function
package com.ccut.aop;
import org.aspectj.lang.ProceedingJoinPoint;
public class Function {
private String fmessage;
private String mmessage;
public Function(){}
public String getFmessage() {
return fmessage;
}
public void setFmessage(String fmessage) {
this.fmessage = fmessage;
}
public String getMmessage() {
return mmessage;
}
public void setMmessage(String mmessage) {
this.mmessage = mmessage;
}
public void f(){
System.out.println(this.getFmessage());
}
public void around(ProceedingJoinPoint pj){
System.out.println("在目标函数之前执行");
try {
pj.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
System.out.println("在目标函数之后执行");
}
}
public void m(){
System.out.println(this.getMmessage());
}
public void mess(String msg){
System.out.println(msg+" 这是返回后的信息");
}
public void err(Throwable ex){
System.out.println("这个错误是:"+ex);
}
}
4.0 搭建测试类 Test.java
package com.ccut.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ccut.aop.Affairs;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("./resources/aop.xml");
Affairs affairs = (Affairs) applicationContext.getBean("affairs");
affairs.PersonA();
affairs.PersonB();
}
}
上面是公共的,也就是说下面的测试都用的是上面的代码
5.0 编写配置文件aop.xml 位于resources文件夹内(这是整合后的,单个功能的配置文件在后面 暂时不用看这个)
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config>
<aop:aspect id="aspect1" ref="function">
<aop:pointcut id="personA" expression="execution(* com.ccut.aop.Affairs.PersonA())"/>
<aop:pointcut id="personB" expression="execution(* com.ccut.aop.Affairs.PersonB())"/>
<!-- <aop:pointcut id="return" expression="execution(* com.ccut.aop.Affairs.*(..))"/>
<aop:before pointcut-ref="personA" method="f"/>
<aop:after method="m" pointcut-ref="personA"/>
<aop:after-returning method="mess" returning="msg" pointcut-ref="return"/> -->
<aop:around method="around" pointcut-ref="personB"/>
</aop:aspect>
</aop:config>
<bean id="affairs" class = "com.ccut.aop.Affairs">
<property name="message1" value="我就是 A 啊 这有什么疑问吗?"/>
<property name="message2" value="我就是 B 啊 这有什么疑问吗?"/>
</bean>
<bean id = "function" class="com.ccut.aop.Function">
<property name="fmessage" value="我可能在你前面执行!"></property>
<property name="mmessage" value="我可能在你后面执行呢!"></property>
</bean>
</beans>
5.1 我们把上面的配置文件拆开看,以便更好的理解
aop的切入形式有一下几种
<aop:before method= ''beforemethod'',pointcut-ref="cut1"/>
<aop:after method= ''aftermethod'',pointcut-ref="cut2"/>
<aop:after-returning method="mess" returning="msg" pointcut-ref="return"/>
<aop:around method="around" pointcut-ref="personB"/>
<aop:after-throwing method="" pointcut-ref="" throwing=""/>
<aop:declare-parents/>这个暂时不解释
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="affairs" class = "com.ccut.aop.Affairs">
<property name="message1" value="我就是 A 啊 这有什么疑问吗?"/>
<property name="message2" value="我就是 B 啊 这有什么疑问吗?"/>
</bean>
<bean id = "function" class="com.ccut.aop.Function">
<property name="fmessage" value="我可能在你前面执行!"></property>
<property name="mmessage" value="我可能在你后面执行呢!"></property>
</bean>
</beans>
上面的简化后的配置文件实现了对事物类 和切面类相关参数的注入
执行简化后的配置文件的结果为:
5.2.1 下面是把功能类的某一方法切入到切入点前面执行的aop.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config>
<aop:aspect id="aspect1" ref="function">
<aop:pointcut id="personA" expression="execution(* com.ccut.aop.Affairs.PersonA())"/>
<!-- 下面是以后要改动的代码↓↓↓↓↓↓↓↓-->
<aop:before pointcut-ref="personA" method="f"/>
<-- 上面是以后要改动的代码↑↑↑↑↑↑↑-->
</aop:aspect>
</aop:config>
<bean id="affairs" class = "com.ccut.aop.Affairs">
<property name="message1" value="我就是 A 啊 这有什么疑问吗?"/>
<property name="message2" value="我就是 B 啊 这有什么疑问吗?"/>
</bean>
<bean id = "function" class="com.ccut.aop.Function">
<property name="fmessage" value="我可能在你前面执行!"></property>
<property name="mmessage" value="我可能在你后面执行呢!"></property>
</bean>
</beans>
执行结果:
5.2.2 把指定方法放在切入点后面执行
配置文件对应位置改为
<aop:after method="m" pointcut-ref="personA"/>
结果为:
5.2.3 在指定方法结束时候执行
配置文件如下
<aop:config>
<aop:aspect id="aspect1" ref="function">
<aop:pointcut id="return" expression="execution(* com.ccut.aop.Affairs.*(..))"/>
<aop:after-returning method="mess" returning="msg" pointcut-ref="return"/>
</aop:aspect>
</aop:config>
测试类:
package com.ccut.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ccut.aop.Affairs;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("./resources/aop.xml");
Affairs affairs = (Affairs) applicationContext.getBean("affairs");
affairs.PersonA();
affairs.PersonB();
affairs.getMessage1();
}
}
结果:
5.2.4 抛出异常后执行 aop:after-throwing 这个方法不能完全处理异常 最终还是会交给jvm
配置文件:
把上面的 < aop:after-returning method=”mess” returning=”msg” pointcut-ref=”return”/> 替换为下面的
<aop:after-throwing method="err" throwing="ex" pointcut-ref="return"/>
主方法中的affairs.getMessage1();改为下面
affairs.error();
结果:
5.2.5 环绕通知增强 aop:around
配置文件:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config>
<aop:aspect id="aspect1" ref="function">
<aop:pointcut id="personB" expression="execution(* com.ccut.aop.Affairs.PersonB())"/>
<aop:around method="around" pointcut-ref="personB"/>
</aop:aspect>
</aop:config>
<bean id="affairs" class = "com.ccut.aop.Affairs">
<property name="message1" value="我就是 A 啊 这有什么疑问吗?"/>
<property name="message2" value="我就是 B 啊 这有什么疑问吗?"/>
</bean>
<bean id = "function" class="com.ccut.aop.Function">
<property name="fmessage" value="我可能在你前面执行!"></property>
<property name="mmessage" value="我可能在你后面执行呢!"></property>
</bean>
</beans>
测试类:
package com.ccut.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ccut.aop.Affairs;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("./resources/aop.xml");
Affairs affairs = (Affairs) applicationContext.getBean("affairs");
affairs.PersonA();
affairs.PersonB();
}
}
结果:
这里注意 环绕通知方法重点一定要有下面这个形参ProceedingJoinPoint pj 如果没有 pj.proceed();这个代码
则被切入的函数不会执行
public void around(ProceedingJoinPoint pj){
System.out.println("在目标函数之前执行");
try {
pj.proceed();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
System.out.println("在目标函数之后执行");
}
}
这里的< aop:declare-parents/>这个暂时不解释