AOP
什么是AOP
- 在軟件業(yè)票罐,AOP為Aspect Oriented Programming的縮寫(xiě)笑旺,意為:面向切面編程量承,通過(guò)預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)题禀。AOP是OOP的延續(xù)鞋诗,是軟件開(kāi)發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容迈嘹,是函數(shù)式編程的一種衍生范型削彬。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離全庸,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性融痛,同時(shí)提高了開(kāi)發(fā)的效率壶笼。
- AOP 采取橫向抽取機(jī)制,取代了傳統(tǒng)縱向繼承體系重復(fù)性代碼雁刷。
- 經(jīng)典應(yīng)用:事物管理覆劈,性能監(jiān)視,安全檢查安券,緩存墩崩,日志等。
- Spring AOP 使用純java實(shí)現(xiàn)侯勉,不需要專(zhuān)門(mén)的編譯過(guò)程和類(lèi)加載器鹦筹,在運(yùn)行期通過(guò)代理方式向目標(biāo)類(lèi)織入增強(qiáng)代碼
- AspectJ是一個(gè)基于Java語(yǔ)言的AOP框架,Spring2.0開(kāi)始址貌,Spring AOP引入對(duì)Aspect的支持铐拐,AspectJ擴(kuò)展了Java語(yǔ)言,提供了一個(gè)專(zhuān)門(mén)的編譯器练对,在編譯時(shí)提供橫向代碼的織入
AOP實(shí)現(xiàn)原理
- aop 底層將采用代理機(jī)制進(jìn)行實(shí)現(xiàn)遍蟋。
- 接口 + 實(shí)現(xiàn)類(lèi):spring采用jdk的動(dòng)態(tài)代理proxy。
- 實(shí)現(xiàn)類(lèi):spring采用cglib字節(jié)碼增強(qiáng)螟凭。
AOP術(shù)語(yǔ)
- 1.target:目標(biāo)類(lèi)虚青,需要被代理的類(lèi)。例如:UserService螺男。
- 2.Joinpoint(連接點(diǎn)):所謂連接點(diǎn)是指那些可能被攔截到的方法棒厘。例如:所有的方法。
- 3.PointCut 切入點(diǎn):已經(jīng)被增強(qiáng)的連接點(diǎn)下隧。例如:addUser()奢人。
- 4.advice 通知/增強(qiáng),增強(qiáng)代碼淆院。例如:after何乎、before。
- Weaving(織入):是指把增強(qiáng)advice應(yīng)用到目標(biāo)對(duì)象target來(lái)創(chuàng)建新的代理對(duì)象proxy的過(guò)程.
- 6.proxy 代理類(lèi)土辩。
- Aspect(切面): 是切入點(diǎn)pointcut和通知advice的結(jié)合支救。
aop1.png
手動(dòng)方式
JDK動(dòng)態(tài)代理
- JDK動(dòng)態(tài)代理 對(duì)“裝飾者”設(shè)計(jì)模式 簡(jiǎn)化。使用前提:必須有接口
1.目標(biāo)類(lèi):接口 + 實(shí)現(xiàn)類(lèi)
2.切面類(lèi):用于存通知 MyAspect
3.工廠類(lèi):編寫(xiě)工廠生成代理
目標(biāo)類(lèi)
public interface UserService {
void addUser();
void updateUser();
void deleteUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("------addUser");
}
@Override
public void updateUser() {
System.out.println("------updateUser");
}
@Override
public void deleteUser() {
System.out.println("------deleteUser");
}
}
切面類(lèi)
public class MyAspect {
public void before(){
System.out.println("方法之前");
}
public void after(){
System.out.println("方法之后");
}
}
工廠類(lèi)
public class MyBeanFactory {
public static UserService createService() {
final UserService userService = new UserServiceImpl();
final MyAspect myAspect = new MyAspect();
/**
* Proxy.newProxyInstance
* 參數(shù)1:loader 類(lèi)加載器,動(dòng)態(tài)代理類(lèi) 運(yùn)行時(shí)創(chuàng)建,任何類(lèi)都需要類(lèi)加載器加載到內(nèi)存
* 一般情況:當(dāng)前類(lèi).getClassLoader();
* 目標(biāo)類(lèi)實(shí)例.getClass.getClassLoader()
* 參數(shù)2: Class[] interfaces代理類(lèi)需要實(shí)現(xiàn)所有的接口
* 方式1:目標(biāo)類(lèi)實(shí)例.getClass().getInterfaces();只能獲得自己接口,不能獲得父元素接口
* 方式2:new Class[]{...}
* 參數(shù)3:InvocationHandler 處理類(lèi),接口必須進(jìn)行實(shí)現(xiàn)類(lèi),一般采用匿名內(nèi)部
* 提供invoke 方法,代理類(lèi)的每一個(gè)方法執(zhí)行,都將調(diào)用一次invoke
* 參數(shù)1:Object proxy:代理對(duì)象
* 參數(shù)2:Mehod method:代理對(duì)象當(dāng)前執(zhí)行的方法描述對(duì)象(反射)
* 執(zhí)行方法名:method.getName()
* 執(zhí)行方法:method.invoke(對(duì)象,實(shí)際參數(shù))
* 參數(shù)3:Object[] args:方法實(shí)際參數(shù)
*
*/
UserService proxService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
myAspect.before();
Object obj = method.invoke(userService,args);
myAspect.after();
return obj;
}
});
return proxService;
}
}
CGLIB 字節(jié)碼增強(qiáng)
- 沒(méi)有接口拷淘,只有實(shí)現(xiàn)類(lèi)搂妻。
- 采用字節(jié)碼增強(qiáng)框架CGLIB,在運(yùn)行時(shí)創(chuàng)建目標(biāo)類(lèi)的子類(lèi)辕棚,從而對(duì)目標(biāo)類(lèi)進(jìn)行增強(qiáng)
實(shí)例
public class CGLIBFactory {
public static UserServiceImpl createService() {
//目標(biāo)類(lèi)
UserServiceImpl userService;
userService = new UserServiceImpl();
//切面類(lèi)
MyAspect myAspect = new MyAspect();
//代理類(lèi)采用cglib 底層創(chuàng)建目標(biāo)類(lèi)的子類(lèi)
//核心類(lèi)
Enhancer enhancer = new Enhancer();
//確定父類(lèi)
enhancer.setSuperclass(userService.getClass());
/**
* 設(shè)置回調(diào)函數(shù),MethodInterceptor 接口等效 jdk InvocationHandler接口
* intercept 等效jdk invoke()
* 參數(shù)4:methodProxy 方法的代理
*/
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
myAspect.before();
Object obj = method.invoke(userService,args);
myAspect.after();
return obj;
}
});
//創(chuàng)建代理類(lèi)
UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
return proxService;
}
}
AOP聯(lián)盟通知類(lèi)型
AOP聯(lián)盟為通知Advice定義了org.aopalliance.aop.Advice
Spring按照通知Advice在目標(biāo)類(lèi)方法的連接點(diǎn)位置欲主,可以分為5類(lèi)
前置通知 org.springframework.aop.MethodBeforeAdvice
在目標(biāo)方法執(zhí)行前實(shí)施增強(qiáng)
后置通知 org.springframework.aop.AfterReturningAdvice
在目標(biāo)方法執(zhí)行后實(shí)施增強(qiáng)
環(huán)繞通知 org.aopalliance.intercept.MethodInterceptor
在目標(biāo)方法執(zhí)行前后實(shí)施增強(qiáng)
異常拋出通知 org.springframework.aop.ThrowsAdvice
在方法拋出異常后實(shí)施增強(qiáng)
引介通知 org.springframework.aop.IntroductionInterceptor
在目標(biāo)類(lèi)中添加一些新的方法和屬性
環(huán)繞通知邓厕,必須手動(dòng)執(zhí)行目標(biāo)方法
try{
//前置通知
//執(zhí)行目標(biāo)方法
//后置通知
} catch(){
//拋出異常通知
}
spring 編寫(xiě)代理:半自動(dòng)
- 讓spring 創(chuàng)建代理對(duì)象,從spring容器中手動(dòng)的獲取代理代理對(duì)象
- 需要jar包: aopallicance-1.0.0.jar ,spring-aop.release.jar
spring 配置
//目標(biāo)類(lèi)
<bean id="userServiceId" class="cn.leyue.a_aop.c_spring.UserServiceImpl"></bean>
//切面類(lèi)(通知)
<bean id="myAspectId" class="cn.leyue.a_aop.c_spring.MyAspect"></bean>
<!--
創(chuàng)建代理類(lèi)
* 使用工廠bean FactoryBean ,底層調(diào)用getObject()返回特殊bean
* ProxyFactoryBean 用于創(chuàng)建代理工程bean,生成特殊代理對(duì)象,
interfaces:確定接口們
通過(guò)<array>可以設(shè)置多個(gè)值
只有一個(gè)值時(shí),value=""
target 確定目標(biāo)類(lèi)
interceptorNames:通知切面類(lèi)的名稱(chēng),類(lèi)型String[],如果設(shè)置一個(gè)值 value=""
optimize:強(qiáng)制使用cglib
<property name="optimize" value="true"></property>
* 底層機(jī)制
如果目標(biāo)類(lèi)接口,采用jdk動(dòng)態(tài)代理
如果沒(méi)有接口,采用cglib 字節(jié)碼增強(qiáng)
如果生命optimize=true 無(wú)論是否有接口,都采用cglib
-->
<bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="cn.leyue.a_aop.c_spring.UserService"></property>
<property name="target" ref="userServiceId"></property>
<property name="interceptorNames" value="myAspectId"></property>
<property name="optimize" value="true"></property>
</bean>
目標(biāo)類(lèi)
public interface UserService {
void addUser();
void updateUser();
void deleteUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("b_cglib------addUser");
}
@Override
public void updateUser() {
System.out.println("b_cglib------updateUser");
}
@Override
public void deleteUser() {
System.out.println("b_cglib------deleteUser");
}
}
切面類(lèi)
/**
* 切面類(lèi)中確定通知,需要實(shí)現(xiàn)不同接口,接口就是規(guī)范,從而確定方法名稱(chēng).
* 采用"環(huán)繞通知"MethodInterceptor
*/
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("c_spring_方法之前");
//手動(dòng)執(zhí)行目標(biāo)方法
Object obj = methodInvocation.proceed();
System.out.println("c_spring_方法之后");
return obj;
}
}
測(cè)試類(lèi)
public class SpringTest {
@Test
public void spring() {
String path = "cn/leyue/a_aop/c_spring/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
UserService service = application.getBean("proxyServiceId", UserService.class);
service.addUser();
service.updateUser();
service.deleteUser();
}
}
spring aop編程:全自動(dòng)
- 從spring 容器獲得目標(biāo)類(lèi)扁瓢,如何配置aop,spring將自動(dòng)生成代理
- 要確定目標(biāo)類(lèi)详恼,aspectj切入點(diǎn)表達(dá)式,導(dǎo)入包引几。
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring 配置
導(dǎo)入命名空間
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
spring aop示例
<?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)類(lèi)-->
<bean id="userServiceId" class="cn.leyue.a_aop.d_spring_auto.UserServiceImpl"></bean>
<!--切面類(lèi)通知-->
<bean id="myAspectId" class="cn.leyue.a_aop.d_spring_auto.MyAspect"></bean>
<bean id="proxyId" class="cn.leyue.a_aop.d_spring_auto.ProxyTest"></bean>
<!--
aop編程
* 導(dǎo)入命名空間
* 使用 <aop:config>進(jìn)行配置
* proxy-target-class="true" 聲明時(shí)使用cglib代理
* <aop:pointcut> 切入點(diǎn),從目標(biāo)對(duì)象獲得具體方法
* <aop:advisor> 特殊的切面,只有一個(gè)通知和一個(gè)切入點(diǎn)
advice-ref 通知引用
pointcut-ref 切入點(diǎn)引用
* 切入點(diǎn)表達(dá)式
execution(* cn.leyue.a_aop.d_spring_auto.*.*(..) )
選擇方法 返回值任意 包 類(lèi)名任意 方法名任意 參數(shù)任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="myPointCut" expression="execution(* cn.leyue.a_aop.d_spring_auto.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"></aop:advisor>
</aop:config>
</beans>`
目標(biāo)類(lèi)
public interface UserService {
void addUser();
void updateUser();
void deleteUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("d_spring_auto------addUser");
}
@Override
public void updateUser() {
System.out.println("d_spring_auto------updateUser");
}
@Override
public void deleteUser() {
System.out.println("d_spring_auto------deleteUser");
}
}
切面類(lèi)
public class MyAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("d_spring_auto_方法之前");
//手動(dòng)執(zhí)行目標(biāo)方法
Object obj = methodInvocation.proceed();
System.out.println("d_spring_auto_方法之后");
return obj;
}
}
測(cè)試
public class TestSpring {
@Test
public void testSpring() {
String path = "cn/leyue/a_aop/d_spring_auto/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
UserService userService = application.getBean("userServiceId", UserService.class);
userService.addUser();
userService.updateUser();
userService.deleteUser();
System.out.println("------------------");
ProxyTest proxy = application.getBean("proxyId", ProxyTest.class);
proxy.sayHello();
}
}
AspectJ
AspectJ介紹
- AspectJ是一個(gè)基于Java 語(yǔ)言的AOP框架昧互。
- Spring2.0以后新增了對(duì)AspectJ切點(diǎn)表達(dá)式支持。
- @AspectJ 是AspectJ1.5新增功能伟桅,通過(guò)JDK5注解技術(shù)敞掘,允許直接在Bean類(lèi)中定義切面,新版本Spring框架楣铁,建議使用AspectJ方式來(lái)開(kāi)發(fā)AOP
- 主要用途:自定義開(kāi)發(fā)
切入點(diǎn)表達(dá)式
1玖雁,execution 用于描述方法
語(yǔ)法:execution(修飾符 返回值 包.類(lèi).方法名(參數(shù)) throws 異常)
修飾符,一般省略
public 公共方法
* 任意
返回值 盖腕,不能省略
void 返回沒(méi)有值
String 返回值字符串
* 任意
包
cn.leyue.a_aop 固定包
cn.leyue.a_aop.*.service a_aop包下面子包任意 (例如:cn.leyue.a_aop.staff.service)
cn.leyue.a_aop.. a_aop包下面的所有子包(含自己)
cn.leyue.a_aop.*.service.. a_aop包下面任意子包赫冬,固定目錄service ,service所有的子包
類(lèi)
UserServiceImpl 指定類(lèi)
*Impl 以Impl結(jié)尾
User* 以User開(kāi)頭
* 任意
方法名,不能省略
addUser 固定方法
add* 以add開(kāi)頭
*Do 以Do結(jié)尾
* 任意
(參數(shù))
() 無(wú)參
(int) 一個(gè)整型參數(shù)
(int,int) 兩個(gè)
(..) 參數(shù)任意
throws 可省略溃列,一般不寫(xiě)
示例
execution(* com.itheima.crm.*.service..*.*(..))
<aop:pointcut expression="execution(* com.itheima.*WithCommit.*(..)) ||
execution(* com.itheima.*Service.*(..))" id="myPointCut"/>
2劲厌,within:匹配包或子包中的方法。
within(com.itheima.aop..*)
3听隐,this:匹配實(shí)現(xiàn)接口的代理對(duì)象中的方法补鼻。
this(com.itheima.aop.user.UserDAO)
4,target:匹配實(shí)現(xiàn)接口的目標(biāo)對(duì)象中的方法
target(com.itheima.aop.user.UserDAO)
5雅任,args:匹配參數(shù)格式符合標(biāo)準(zhǔn)的方法
args(int,int)
6风范,bean(id) 對(duì)指定的bean所有的方法
bean('userServiceId')
AspectJ 通知類(lèi)型
- aop聯(lián)盟定義通知類(lèi)型,具有特性接口椿访,必須實(shí)現(xiàn)乌企,從而確定方法名稱(chēng)虑润。
- aspectj 通知類(lèi)型成玫,只定義類(lèi)型名稱(chēng)。已經(jīng)方法格式拳喻。
類(lèi)型
before:前置通知(應(yīng)用:各種校驗(yàn))
在方法執(zhí)行前執(zhí)行哭当,如果通知拋出異常,阻止方法運(yùn)行冗澈。
afterReturning:后置通知(應(yīng)用:常規(guī)數(shù)據(jù)處理)
方法正常返回后執(zhí)行钦勘,如果方法中拋出異常,通知無(wú)法執(zhí)行亚亲。
必須在方法執(zhí)行后才執(zhí)行彻采,所以可以獲得方法的返回值腐缤。
around:環(huán)繞通知(應(yīng)用:十分強(qiáng)大,可以做任何事情)
方法執(zhí)行前后分別執(zhí)行肛响,可以阻止方法的執(zhí)行岭粤。
必須手動(dòng)執(zhí)行目標(biāo)方法。
afterThrowing:拋出異常通知(應(yīng)用:包裝異常信息)
方法拋出異常后執(zhí)行特笋,如果方法沒(méi)有拋出異常剃浇,無(wú)法執(zhí)行。
after:最終通知(應(yīng)用:清理現(xiàn)場(chǎng))
方法執(zhí)行完畢后執(zhí)行猎物,無(wú)論方法中是否出現(xiàn)異常
aspectJ.png
AspectJ 需要導(dǎo)入jar包
aop 聯(lián)盟規(guī)范 spring aop 實(shí)現(xiàn) aspect規(guī)范 spring aspect 實(shí)現(xiàn)
Aspectjar.png
aspect 基于xml
- 目標(biāo)類(lèi): 接口 + 實(shí)現(xiàn)
- 切面類(lèi): 編寫(xiě)多個(gè)通知虎囚,采用aspectj 通知名稱(chēng)任意(方法名任意)
- aop編程,將通知應(yīng)用到目標(biāo)類(lèi)
切面類(lèi)
/**
* 切面類(lèi),含有多個(gè)通知
*/
public class MyAspect {
public void myBefore(JoinPoint joinPoint) {
System.out.println("前置通知: " + joinPoint.getSignature().getName());
System.out.println("參數(shù): "+ Arrays.asList(joinPoint.getArgs()));
}
public void myAfterReturning(JoinPoint joinPoint, Object ret) {
System.out.println("后置通知: " + joinPoint.getSignature().getName() + ",----->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環(huán)繞通知: 前");
Object obj = joinPoint.proceed();
System.out.println("環(huán)繞通知: 后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
System.out.println("拋出異常通知: "+e.getMessage());
}
public void myAfter(JoinPoint joinPoint) {
System.out.println("最終通知");
}
}
spring 配置
<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
">
<!-- 1 創(chuàng)建目標(biāo)類(lèi) -->
<bean id="userServiceId" class="cn.leyue.a_aop.e_aspect.a_xml.UserServiceImpl"></bean>
<!-- 2 創(chuàng)建切面類(lèi)(通知) -->
<bean id="myAspectId" class="cn.leyue.a_aop.e_aspect.a_xml.MyAspect"></bean>
<!-- 3 aop編程
<aop:aspect> 將切面類(lèi) 聲明“切面”蔫磨,從而獲得通知(方法)
ref 切面類(lèi)引用
<aop:pointcut> 聲明一個(gè)切入點(diǎn)淘讥,所有的通知都可以使用。
expression 切入點(diǎn)表達(dá)式
id 名稱(chēng)质帅,用于其它通知引用
-->
<aop:config>
<aop:aspect ref="myAspectId">
<aop:pointcut id="myPointCut" expression="execution(* cn.leyue.a_aop.e_aspect.a_xml.UserServiceImpl.*(..))"></aop:pointcut>
<!--前置通知-->
<aop:before method="" pointcut="" pointcut-ref=""/>
method : 通知适揉,及方法名
pointcut :切入點(diǎn)表達(dá)式,此表達(dá)式只能當(dāng)前通知使用煤惩。
pointcut-ref : 切入點(diǎn)引用嫉嘀,可以與其他通知共享切入點(diǎn)。
通知方法格式:public void myBefore(JoinPoint joinPoint){
參數(shù)1:org.aspectj.lang.JoinPoint 用于描述連接點(diǎn)(目標(biāo)方法)魄揉,獲得目標(biāo)方法名等
<aop:before method="myBefore" pointcut-ref="myPointCut"></aop:before>
<!--后置通知-->
3.2后置通知 ,目標(biāo)方法后執(zhí)行剪侮,獲得返回值
<aop:after-returning method="" pointcut-ref="" returning=""/>
returning 通知方法第二個(gè)參數(shù)的名稱(chēng)
通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
參數(shù)1:連接點(diǎn)描述
參數(shù)2:類(lèi)型Object,參數(shù)名 returning="ret" 配置的
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret"></aop:after-returning>
3.3 環(huán)繞通知
<aop:around method="" pointcut-ref=""/>
通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
返回值類(lèi)型:Object
方法名:任意
參數(shù):org.aspectj.lang.ProceedingJoinPoint
拋出異常
執(zhí)行目標(biāo)方法:Object obj = joinPoint.proceed();
<aop:around method="myAround" pointcut-ref="myPointCut"></aop:around>
<!--拋出異常-->
<aop:after-throwing method="" pointcut-ref="" throwing=""/>
throwing :通知方法的第二個(gè)參數(shù)名稱(chēng)
通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
參數(shù)1:連接點(diǎn)描述對(duì)象
參數(shù)2:獲得異常信息洛退,類(lèi)型Throwable 瓣俯,參數(shù)名由throwing="e" 配置
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"></aop:after-throwing>
<!--最終通知-->
<aop:after method="myAfter" pointcut-ref="myPointCut"></aop:after>
</aop:aspect>
</aop:config>
</beans>
aspect 基于注解
spring 配置
<?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"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<!--掃描 注解類(lèi)-->
<context:component-scan base-package="cn.leyue.a_aop.e_aspect.b_anno"></context:component-scan>
<!--確定 aop注解生效-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
替換AOP
- 必須進(jìn)行aspectj自動(dòng)代理
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<context:component-scan base-package="cn.leyue.a_aop.e_aspect.b_anno"></context:component-scan>
切面類(lèi)
/**
* 切面類(lèi),含有多個(gè)通知
*/
@Component
@Aspect
public class MyAspect {
//聲明公共變量
@Pointcut("execution(* cn.leyue.a_aop.e_aspect.b_anno.UserServiceImpl.*(..))")
private void myPointCut() {
}
//切入點(diǎn)當(dāng)前有效
// @Before("execution(* cn.leyue.a_aop.e_aspect.b_anno.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint) {
System.out.println("前置通知: " + joinPoint.getSignature().getName());
System.out.println("參數(shù): "+ Arrays.asList(joinPoint.getArgs()));
}
// @AfterReturning(value = "myPointCut()",returning = "ret")
public void myAfterReturning(JoinPoint joinPoint, Object ret) {
System.out.println("后置通知: " + joinPoint.getSignature().getName() + ",----->" + ret);
}
// @Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環(huán)繞通知: 前");
Object obj = joinPoint.proceed();
System.out.println("環(huán)繞通知: 后");
return obj;
}
@AfterThrowing(value = "myPointCut()",throwing = "e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
System.out.println("拋出異常通知: "+e.getMessage());
}
// @After(value="myPointCut()")
public void myAfter(JoinPoint joinPoint) {
System.out.println("最終通知");
}
}
public interface UserService {
void addUser(String username);
String updateUser();
void deleteUser();
}
@Service("userServiceId")
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("b_anno------addUser "+username);
}
@Override
public String updateUser() {
System.out.println("b_anno------updateUser");
int i= 1/0;
return "back";
}
@Override
public void deleteUser() {
System.out.println("b_anno------deleteUser");
}
}
測(cè)試注解
public class TestAspectAnno {
@Test
public void testanno() {
String path ="cn/leyue/a_aop/e_aspect/b_anno/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
UserService userService = application.getBean("userServiceId",UserService.class);
userService.addUser("anno");
userService.updateUser();
userService.deleteUser();
}
}
JdbcTemplate
- spring 提供用于操作JDBC工具類(lèi),類(lèi)似DBUtils
- 依賴(lài)連接池DataSource(數(shù)據(jù)源)
環(huán)境搭建
導(dǎo)入jar包
jdbc1.png
javabean
public class Building {
private String buname;
private int id;
private String buaddress;
private double aveprice;
public String getBuname() {
return buname;
}
public void setBuname(String buname) {
this.buname = buname;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBuaddress() {
return buaddress;
}
public void setBuaddress(String buaddress) {
this.buaddress = buaddress;
}
public double getAveprice() {
return aveprice;
}
public void setAveprice(double aveprice) {
this.aveprice = aveprice;
}
@Override
public String toString() {
return "Building{" +
"buname='" + buname + '\'' +
", id=" + id +
", buaddress='" + buaddress + '\'' +
", aveprice=" + aveprice +
'}';
}
}
使用api
@Test
public void jdbc() {
//1 創(chuàng)建數(shù)據(jù)源(連接池)dbcp
BasicDataSource dataSource = new BasicDataSource();
//基本四項(xiàng)
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8");
dataSource.setUsername("root");
dataSource.setPassword("");
//創(chuàng)建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//通過(guò)api操作
String sql = "select * from fc_building limit ?";
List<Building> datas = jdbcTemplate.query(sql, new Object[]{10}, ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
for (Building building : datas) {
System.out.println(building);
}
}
DAO
public class BuildingDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Building> findAll() {
List<Building> datas = jdbcTemplate.query("select * from fc_building limit ?",new Object[]{10},
ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
return datas;
}
}
配置DBCP
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSourceId" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
<bean id="jdbcTemplateId" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
<bean id="buildingDaoId" class="cn.leyue.jdbc.dbcp.BuildingDao">
<property name="jdbcTemplate" ref="jdbcTemplateId"></property>
</bean>
</beans>
配置的C3P0
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value=""></property>
</bean>
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
<bean id="buildingDaoId" class="cn.leyue.jdbc.dbcp.BuildingDao">
<property name="jdbcTemplate" ref="template"></property>
</bean>
</beans>
使用JdbcDaoSupport
dao 需要繼承 JdbcDaoSupport
public class BuildingSupportDao extends JdbcDaoSupport {
public List<Building> findAll() {
List<Building> datas = getJdbcTemplate().query("select * from fc_building limit ?",new Object[]{10},
ParameterizedBeanPropertyRowMapper.newInstance(Building.class));
return datas;
}
}
spring 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8"></property>
<property name="user" value="root"></property>
<property name="password" value=""></property>
</bean>
<!--
dao 繼承 JdbcDaoSupport兵怯,之后只需要注入數(shù)據(jù)源彩匕,底層將自動(dòng)創(chuàng)建模板
-->
<bean id="buildingDaoId" class="cn.leyue.jdbc.support.BuildingSupportDao">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
</beans>
配置properties
properties 文件
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/haoju_cn?useUnicode=true&characterEncoding=UTF-8
jdbc.user=root
jdbc.password=
spring配置
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--
加載配置文件
"classpath" 前綴表示src下
在配置文件之后通過(guò)${key}獲得內(nèi)容
-->
<context:property-placeholder location="classpath:cn/leyue/jdbc/properties/jdbcInfo.properties"/>
<!--創(chuàng)建數(shù)據(jù)源c3p0-->
<bean id="dataSourceId" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="user" value="${jdbc.user}"></property>
</bean>
<bean id="daoId" class="cn.leyue.jdbc.support.BuildingSupportDao">
<property name="dataSource" ref="dataSourceId"></property>
</bean>
</beans>
測(cè)試類(lèi)
@Test
public void c3p0() {
String path = "cn/leyue/jdbc/c3p0/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
BuildingDao dao = application.getBean("buildingDaoId", BuildingDao.class);
System.out.println(" ===c3p0=== ");
List<Building> datas = dao.findAll();
for (Building building : datas) {
System.out.println(building);
}
}
@Test
public void support() {
String path = "cn/leyue/jdbc/support/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
BuildingSupportDao dao = application.getBean("buildingDaoId", BuildingSupportDao.class);
System.out.println(" ===support=== ");
List<Building> datas = dao.findAll();
for (Building building : datas) {
System.out.println(building);
}
}
@Test
public void propertis() {
String path = "cn/leyue/jdbc/properties/beans.xml";
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext(path);
BuildingSupportDao dao = application.getBean("daoId", BuildingSupportDao.class);
System.out.println(" ===propertis=== ");
List<Building> datas = dao.findAll();
for (Building building : datas) {
System.out.println(building);
}
}