前幾篇已經(jīng)對(duì)AOP中的相關(guān)概念做了解釋,但是都是通過編碼方式實(shí)現(xiàn)的怠硼,每次都需要通過ProxyFactory去創(chuàng)建代理蕊唐,接下來我們介紹Spring中的自動(dòng)代理方式來實(shí)現(xiàn)AOP,基于Schema
配置文件方式和基于@AspectJ
注解的方式酷含。當(dāng)然自動(dòng)代理實(shí)現(xiàn)的機(jī)制,放到后面的章節(jié)分析汪茧,本篇權(quán)當(dāng)溫習(xí)椅亚,也為接下來的源碼分析做好鋪墊。
1.普通切面
- 目標(biāo)對(duì)象
package com.lyc.cn.v2.day06;
public interface Animal {
void sayHello(String name,int age);
void sayException(String name, int age);
}
package com.lyc.cn.v2.day06;
public class Cat implements Animal {
@Override
public void sayHello(String name, int age) {
System.out.println("--調(diào)用被增強(qiáng)方法");
}
@Override
public void sayException(String name, int age) {
System.out.println("==拋出異常:" + 1 / 0);
}
}
- 切面類
package com.lyc.cn.v2.day06;
import org.aspectj.lang.ProceedingJoinPoint;
public class CatAspect {
/**
* 前置增強(qiáng)
*/
public void beforeAdvice(String name, int age) {
System.out.println("==前置增強(qiáng)舱污,name:" + name + "呀舔,age:" + age);
}
/**
* 后置異常增強(qiáng)
*/
public void afterExceptionAdvice(String name, int age) {
System.out.println("==后置異常增強(qiáng),name:" + name + "扩灯,age:" + age);
}
/**
* 后置返回增強(qiáng)
*/
public void afterReturningAdvice(String name, int age) {
System.out.println("==后置返回增強(qiáng)媚赖,name:" + name + "霜瘪,age:" + age);
}
/**
* 后置最終增強(qiáng)
*/
public void afterAdvice(String name, int age) {
System.out.println("==后置最終增強(qiáng),name:" + name + "惧磺,age:" + age);
}
/**
* 環(huán)繞增強(qiáng)
*/
public Object roundAdvice(ProceedingJoinPoint p, String name, int age) {
System.out.println("==環(huán)繞增強(qiáng)開始颖对,name:" + name + ",age:" + age);
Object o = null;
try {
o = p.proceed();
Object[] args = p.getArgs();
if (null != args) {
for (int i = 0; i < args.length; i++) {
System.out.println("==環(huán)繞增強(qiáng)參數(shù)值:" + args[i]);
}
}
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("==環(huán)繞增強(qiáng)結(jié)束磨隘,name:" + name + "惜互,age:" + age);
return o;
}
}
- 配置文件
<?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: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">
<!-- 目標(biāo)對(duì)象 -->
<bean id="cat" class="com.lyc.cn.v2.day06.Cat"/>
<!-- 切面類-->
<bean id="catAspect" class="com.lyc.cn.v2.day06.CatAspect"/>
<!--AOP配置(一)-->
<aop:config proxy-target-class="true">
<!-- 切入點(diǎn)-->
<aop:pointcut id="pointcut" expression="execution(* com.lyc.cn.v2.day06..*.*(..)) and args(name,age)"/>
<aop:aspect ref="catAspect" order="0">
<!--前置增強(qiáng),在切入點(diǎn)選擇的方法之前執(zhí)行-->
<aop:before method="beforeAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
<!--后置異常增強(qiáng)琳拭,在切入點(diǎn)選擇的方法拋出異常時(shí)執(zhí)行-->
<aop:after-throwing method="afterExceptionAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
<!--后置返回增強(qiáng),在切入點(diǎn)選擇的方法正常返回時(shí)執(zhí)行-->
<aop:after-returning method="afterReturningAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
<!--后置最終增強(qiáng)描验,在切入點(diǎn)選擇的方法返回時(shí)執(zhí)行白嘁,不管是正常返回還是拋出異常都執(zhí)行-->
<aop:after method="afterAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
<!--
環(huán)繞增強(qiáng),環(huán)繞著在切入點(diǎn)選擇的連接點(diǎn)處的方法所執(zhí)行的通知膘流,可以決定目標(biāo)方法是否執(zhí)行絮缅,
什么時(shí)候執(zhí)行,執(zhí)行時(shí)是否需要替換方法參數(shù)呼股,執(zhí)行完畢是否需要替換返回值
-->
<aop:around method="roundAdvice" pointcut-ref="pointcut" arg-names="p,name,age"/>
</aop:aspect>
</aop:config>
</beans>
- 測(cè)試類及結(jié)果
package com.lyc.cn.v2.day06;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
Cat cat = ctx.getBean("cat", Cat.class);
cat.sayHello("美美", 3);
}
@Test
public void test2() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
Cat cat = ctx.getBean("cat", Cat.class);
cat.sayException("美美", 3);
}
}
// 測(cè)試1
==前置增強(qiáng)耕魄,name:美美,age:3
==環(huán)繞增強(qiáng)開始彭谁,name:美美吸奴,age:3
--調(diào)用被增強(qiáng)方法
==環(huán)繞增強(qiáng)參數(shù)值:美美
==環(huán)繞增強(qiáng)參數(shù)值:3
==環(huán)繞增強(qiáng)結(jié)束,name:美美缠局,age:3
==后置最終增強(qiáng)则奥,name:美美,age:3
==后置返回增強(qiáng)狭园,name:美美读处,age:3
// 測(cè)試2
==前置增強(qiáng),name:美美唱矛,age:3
==環(huán)繞增強(qiáng)開始罚舱,name:美美,age:3
==環(huán)繞增強(qiáng)結(jié)束绎谦,name:美美管闷,age:3
==后置最終增強(qiáng),name:美美燥滑,age:3
==后置返回增強(qiáng)渐北,name:美美,age:3java.lang.ArithmeticException: / by zero
at com.lyc.cn.v2.day06.Cat.sayException(Cat.java:12)
at com.lyc.cn.v2.day06.Cat$$FastClassBySpringCGLIB$$336350b6.invoke(<generated>
相信大家對(duì)這樣的配置已經(jīng)非常熟悉了铭拧,而且在配置文件中已經(jīng)有了比較完善的說明赃蛛,而且Schema的配置方式已經(jīng)不是那么流行恃锉,所以我們不做過多的介紹。
2.引介增強(qiáng)
Spring引入允許為目標(biāo)類對(duì)象引入新的接口呕臂。
- 引介接口和實(shí)現(xiàn)
package com.lyc.cn.v2.day06;
/**
* 引入
* @author: LiYanChao
* @create: 2018-10-28 15:48
*/
public interface IIntroduce {
void sayIntroduce();
}
package com.lyc.cn.v2.day06;
/**
* @author: LiYanChao
* @create: 2018-10-28 15:48
*/
public class IntroduceImpl implements IIntroduce {
@Override
public void sayIntroduce() {
System.out.println("--引入");
}
}
- 修改配置文件配置引介增強(qiáng)
在<aop:aspect/>
標(biāo)簽中加入如下配置:
<!--
引入
1破托、types-matching:匹配需要引入接口的目標(biāo)對(duì)象的AspectJ語法類型表達(dá)式。
2歧蒋、implement-interface:定義需要引入的接口土砂。
3、default-impl和delegate-ref:定義引入接口的默認(rèn)實(shí)現(xiàn)谜洽,二者選一萝映,
default-impl是接口的默認(rèn)實(shí)現(xiàn)類全限定名,而delegate-ref是默認(rèn)的實(shí)現(xiàn)的委托Bean名阐虚。
-->
<aop:declare-parents types-matching="com.lyc.cn.v2.day06.Cat"
implement-interface="com.lyc.cn.v2.day06.IIntroduce"
default-impl="com.lyc.cn.v2.day06.IntroduceImpl"/>
- 測(cè)試及結(jié)果
@Test
public void test3() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
// 注意:getBean獲取的是cat
IIntroduce introduce = ctx.getBean("cat", IIntroduce.class);
introduce.sayIntroduce();
}
--引入
3.總結(jié)
本篇主要回顧一下基于Schema的AOP的配置方式序臂,都是基于配置文件,當(dāng)然這里涉及到的知識(shí)點(diǎn)也很多实束,這里只是做了簡(jiǎn)單的介紹奥秆,關(guān)于更多的配置,大家可以參考Spring的官方文檔咸灿。