Spring是什么
*Spring是一個開源框架,為了解決企業(yè)應(yīng)用開發(fā)的復(fù)雜性而創(chuàng)建的,但現(xiàn)在已經(jīng)不止應(yīng)用于企業(yè)應(yīng)用
*是一個輕量級的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架
——從大小與開銷兩方面而言SPringle都是輕量的
——通過控制反轉(zhuǎn)(IoC)的技術(shù)達(dá)到松耦合的目的

——包含并管理應(yīng)用對象的配置和生命周期,這個意義上是一種容器
——將簡單的組件配置,組合成為復(fù)雜的應(yīng)用,這個意義上是框架
Spring帶來了復(fù)雜JavaEE開發(fā)的春天
什么是框架

框架的特點(diǎn)
——半成品
——封裝了特定處理流程和控制邏輯
——成熟的,不斷升級改進(jìn)的軟件
框架和類庫的區(qū)別
——框架一般是封裝了邏輯,高內(nèi)聚的,類庫則是松散的工具組合
——框架專注于某以領(lǐng)域,類庫則是更通用的?
為什么使用框架
*軟件日趨復(fù)雜
*重用度高,開發(fā)效率和質(zhì)量提高
*軟件設(shè)計(jì)人員要專注于對領(lǐng)域的了解,是需求更加充分
*易于上手,快速解決問題
IOC
接口
*用于溝通的中介物的抽象化
*實(shí)體把自己提供給外界的一種抽象化說明,用以有內(nèi)部操作分離出外部溝通方法,使其能被修改內(nèi)部而不影響外界其他實(shí)體與其交互的方式
*對應(yīng)Java接口即聲明,聲明了哪些方法是對外公開提供的
*在Java8中,接口可以擁有方法體
面向接口編程



IOC控制反轉(zhuǎn):哪些方面的控制被反轉(zhuǎn)了呢?
? 獲取依賴對象的過程被反轉(zhuǎn)了,控制被反轉(zhuǎn)之后,獲得依賴的對象的過程被反轉(zhuǎn)了,獲取依賴的對象有自身管理變成了IOC容器主動注入,于是,他給控制反轉(zhuǎn)去了更合適的名字“依賴”注入
IOC中所有的對象都叫做bean


bean容器初始化?


Spring注入
*Spring注入是指在啟動Spring容器加載bean配置的時候,完成對變量的賦值行為
*常用的兩種注入方式
——設(shè)值注入

——構(gòu)造注入

DAO:對于數(shù)據(jù)庫的訪問
Service:處理業(yè)務(wù)邏輯的部分
Bean
*Bean的配置項(xiàng)
id:配置項(xiàng)中的唯一標(biāo)識
Class:具體要實(shí)例化的一個類(必須的)
Scope:范圍,作用域
Constructor arguments:構(gòu)造器的參數(shù)
Properties:屬性
Autowiring mode:自動裝配的模式
lazy-initialization mode:懶加載模式
Intialization/desturction method:初始化和銷毀的方法
*Bean的作用域:??

*Bean的生命周期:
- 定義:在Bean的配置文件(xml)中配置的Bean,Bean的id以及Bean的Class
- 初始化:加載并配置文件Bean,并初始化生成Bean的實(shí)例


- 使用:在單元測試中或者實(shí)際使用中從Bean中取出一個Bean的實(shí)例,去調(diào)用他的方法
- 銷毀:在baen停止的時候,銷毀這個Bean產(chǎn)生的實(shí)例



*Bean的自動裝配
*Resources&ResourcesLoader
Aware
*Spring中提供了一些以Aware結(jié)尾的接口,實(shí)現(xiàn)了Aware接口的bean在被初始化之后,可以獲得相應(yīng)的資源
*通過Aware接口,可以對Spring相應(yīng)資源進(jìn)行操作(一定要慎重)
*為對Spring進(jìn)行簡單的擴(kuò)展提供了方便的入口
----------------------------------------------------------------------------------------------------------------------------------------------------Spring學(xué)習(xí)筆記
IOC
控制反轉(zhuǎn),將原本程序中手動創(chuàng)建UserService對象的控制權(quán),交由Spring框架管理
簡單說,就是把創(chuàng)建UserService對象控制權(quán)被反轉(zhuǎn)到了Spring框架
DI 依賴注入
就是在Spring創(chuàng)建這個對象的過程中,將這個對象所依賴的屬性注入進(jìn)去
Bean標(biāo)簽的一些常用的屬性
id和name
一般情況下,裝配一個bean的時候,通過指定一個id屬性作為Bean的名稱
id屬性在ioc容器中必須的唯一的
如果bean的名稱中有特殊字符,就需要使用name屬性
class
class用于設(shè)置一個類的全路徑,用Spring來生成這個類的實(shí)例和反射
由scope配置
singleton是默認(rèn)值,單例
prototype,每一次都會創(chuàng)建一個新的實(shí)例,也就是說是多例的?
Spring的注解方式注入
@Component、@Repository、@Service、@Comtroller等都是相當(dāng)于在配置文件中對<bean></bean>中的id的配置
@Component("userService")//這就相當(dāng)于是<bean></bean>的id;
?
<beanid="userService"class="com.imooc.ioc.demo5.UserService">
如果是普通類型用@Value,這個注解給key設(shè)值
/*
正常這時候得需要一個set方法
然后在配置文件中使用<property name="name" value="張三"></property>進(jìn)行設(shè)值
*/
@Value("米飯")
privateStringsomething;
?
/*
如果提供了set方法,這時候注解需要添加在set方法前
*/
@Value("米飯")
publicvoidsetSomething(Stringsomething) {
this.something=something;
?? }
如果是對象類型的話用一下方法,例如:UserDao的注解
@Autowired
@Qualifier("userDao")
privateUserDaouserDao;
?
@Repository("userDao")
publicclassUserDao{
publicvoidsave(){
System.out.println("Dao層保存數(shù)據(jù)");
?? }
}
//其中的@Qualifier("userDao")和@Repository("userDao")中的userDao名稱一定要一致,否則會報錯
?
?
//
@Resource(name="userDao")就相當(dāng)于@Autowired@Qualifier("userDao")//Resource也是強(qiáng)制用名稱注入
Spring的其他注解
@Component("bean1")
publicclassBean1{
?
@PostConstruct
publicvoidinit(){
System.out.println("initBean......");
?? }
?
publicvoidsay(){
System.out.println("sayBean.......");
?? }
?
@PreDestroy
publicvoiddestory(){
System.out.println("destoryBean..........");
?? }
=======================================================================================
@Component("bean2")
@Scope("prototype")
publicclassBean2{
}
======================================================================================
@Test
publicvoiddemo3(){
ClassPathXmlApplicationContextapplicationContext=newClassPathXmlApplicationContext("applicationContext.xml");
Demo2bean1=(Demo2)applicationContext.getBean("demo2");
Demo2bean2=(Demo2)applicationContext.getBean("demo2");
?
System.out.println(bean1==bean2);
?
?? }
===================================================================================
當(dāng)bean2的Scope為默認(rèn)值singleton的為單例的 ,bean1 == bean2的值為true;
當(dāng)bean2的Scope為prototype的為多例的 ,bean1 == bean2的值為false;
傳統(tǒng)xml配置與注解配置混合使用
publicclassProduceService{
@Resource(name="categoryDao")
privateCategoryDaocategoryDao;
?
@Resource(name="productDao")
privateProductDaoproductDao;
?
// ?? public void setCategoryDao(CategoryDao categoryDao) {
// ? ? ?? this.categoryDao = categoryDao;
// ?? }
//
// ?? public void setProductDao(ProductDao productDao) {
// ? ? ?? this.productDao = productDao;
// ?? }
?
publicvoidsave(){
System.out.println("ProduceServicede的save()方法被執(zhí)行了");
categoryDao.save();
productDao.save();
?? }
}
=========================================================================================
<context:annotation-config/>
<beanid="produceService"class="com.imooc.demo3.ProduceService">
<!--<propertyname="categoryDao"ref="catrgoryDao"></property>-->
<!--<propertyname="productDao"ref="productDao"></property>-->
</bean>
?
<beanid="productDao"class="com.imooc.demo3.ProductDao">
</bean>
?
<beanid="categoryDao"class="com.imooc.demo3.CategoryDao"></bean>
<context:annotation-config/>這個是啟動屬性注入
正常是通過set方法
publicvoidsetCategoryDao(CategoryDaocategoryDao) {
// ? ? ?? this.categoryDao = categoryDao;
// ?? }
//
// ?? public void setProductDao(ProductDao productDao) {
// ? ? ?? this.productDao = productDao;
// ?? }
然后使用xml配置文件配置
<propertyname="categoryDao"ref="catrgoryDao"></property>
<propertyname="productDao"ref="productDao"></property>
啟用<context:annotation-config/>后,可以通過注解方式來代替先創(chuàng)建set方法然后在xml配置文件中配置
@Resource(name="categoryDao")
privateCategoryDaocategoryDao;
?
@Resource(name="productDao")
privateProductDaoproductDao;
Spring AOP
publicclassUserDaoImplimplementsUserDao{
publicvoidsave(Useruser){
publicvoidcheckPrivilege(){
checkPrivilege()
...保存用戶
?? }
publicvoidupdate(Useruser){
...更新用戶
?? }
publicvoiddelete(Useruser){
...刪除用戶
?? }
publicListfind( ){
...查詢用戶
?? }
publicvoidcheckPrivilege(){
//檢查權(quán)限
?? }
}
?
這個類中保存用戶時,調(diào)用checkPrivilege()方法檢查權(quán)限。但是這只是一個類,如果有很多個類,要再每一個來中都寫這么一個方法然后調(diào)用時非常麻煩的
傳統(tǒng)方法:縱向繼承
publicclassBaseDaoImpl{
publicvoidcheckPrivilege(){
?? }
}
?
publicclassUserDaoImplextendsBaseDaoImpl{
publicvoidsave(Useruser){
checkPrivilege()
//保存用戶
?? }
}
沒有使用AOP的方式:
定義一個父類的實(shí)現(xiàn)類,父類中有一個檢查權(quán)限的方法
讓其他的類繼承這個父類的實(shí)現(xiàn)類,子類中可以有父類中的方法,直接調(diào)用checkPrivilege()檢查權(quán)限
使用AOP的動態(tài)代理方法:采用橫向抽取機(jī)制
SpringAOP使用純java實(shí)現(xiàn),不需要專門的編譯過程和類加載器,在運(yùn)行期通過代理方式想目標(biāo)類織入增強(qiáng)代碼
AOP的相關(guān)術(shù)語:
publicclassUserDaoImplimplementsUserDao{
publicvoidsave(Useruser){
publicvoidcheckPrivilege(){
checkPrivilege()
...保存用戶
?? }
publicvoidupdate(Useruser){
...更新用戶
?? }
publicvoiddelete(Useruser){
...刪除用戶
?? }
publicListfind( ){
...查詢用戶
?? }
publicvoidcheckPrivilege(){
//檢查權(quán)限
?? }
}
Joinpoint(連接點(diǎn)):指的是可以攔截到的點(diǎn)
增刪改查這些方法都可以被增強(qiáng),這些方法成為是連接點(diǎn)
Pointcut(切入點(diǎn)):指的是真正被攔截到的點(diǎn)
指想對save()方法進(jìn)行增強(qiáng)(做權(quán)限校驗(yàn)),save方法稱為是切入點(diǎn)
Advice(通知):攔截后要做的事:
對save()方法進(jìn)行權(quán)限校驗(yàn),權(quán)限校驗(yàn)的方法稱之為通知
通知有前置和后置以及環(huán)繞通知
前置通知:比如說想在save方法之前做權(quán)限校驗(yàn),這就叫前置通知
后置通知:比如說要在delete方法做一個日志記錄,這就叫后置通知
環(huán)繞通知:在之前和之后都會做一些事情
Target(目標(biāo)):被增強(qiáng)的對象,例如:UserDaoImpl
Weaving(織入):將Advice應(yīng)用到Target的過程
將權(quán)限校驗(yàn)應(yīng)用到UserDaoImpl的save()方法中的整個過程
Proxy(代理對象):被應(yīng)用了增強(qiáng)后,產(chǎn)生的一個代理對象
Aspect(切面):就是切入點(diǎn)和通知的組合
JDK的動態(tài)代理
定義一個接口
publicinterfaceUserDao{
publicvoidsave();
?
publicvoiddelete();
?
publicvoidupdate();
?
publicvoidfind();
}
接口的實(shí)現(xiàn)類
publicclassUserDaoImplimplementsUserDao{
?
publicvoidsave() {
System.out.println("保存用戶");
?? }
?
publicvoiddelete() {
System.out.println("刪除用戶");
?? }
?
publicvoidupdate() {
System.out.println("修改用戶");
?? }
?
publicvoidfind() {
System.out.println("查詢用戶");
?? }
}
編寫一個動態(tài)代理類
/*
這個構(gòu)造方法的作用是獲取到需要增強(qiáng)的對象
*/
publicMyjdkProxy(UserDaouserDao){
this.userDao=userDao;
?? }
=====================================================================================
publicObjectcreateProxy(){//用createProxy()這個方法產(chǎn)生一個代理,首選jdk的動態(tài)代理,因?yàn)閖dk的動態(tài)代理可以對實(shí)現(xiàn)了接口的類實(shí)現(xiàn)代理
/*
傳入的參數(shù):類加載器userDao.getClass().getClassLoader();實(shí)現(xiàn)的接口userDao.getClass().getInterfaces();第三個參數(shù)是一個接口InvocationHandler
*/
Objectproxy=Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
returnproxy;
?? }
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{
if("save".equals(method.getName())){
System.out.println("權(quán)限校驗(yàn)");
returnmethod.invoke(userDao,args);
? ? ?? }
returnmethod.invoke(userDao,args);
?? }
====================================================================================
/*
編寫測試類,使用代理
*/
UserDaouserDao=newUserDaoImpl();
?
?
UserDaoproxy=(UserDao)newMyjdkProxy(userDao).createProxy();
proxy.save();
proxy.delete();
proxy.update();
proxy.find();
?? }
CGLIB動態(tài)代理
底層:生成了一個類來繼承目標(biāo)類
對于不使用接口的業(yè)務(wù)層,無法使用jdk的動態(tài)代理
CGLIB采用非常底層字節(jié)碼技術(shù),可以為一個類創(chuàng)建字類,解決無接口代理問題
publicObjectcreateProxy(){
//1.創(chuàng)建一個CGLIB的核心類
Enhancerenhancer=newEnhancer();
//2.設(shè)置父類
enhancer.setSuperclass(object.getClass());
//3.設(shè)置回調(diào)
enhancer.setCallback(this);
//4.生成代理
Objectproxy=enhancer.create;
returnproxy;
}
代理知識總結(jié):
Spring在運(yùn)行期,生成動態(tài)代理對象,不需要特殊的編譯器
Spring AOP的底層就是通過jdk的動態(tài)代理或者CGLIB動態(tài)代理技術(shù),為目標(biāo)Bean執(zhí)行橫向織入
若目標(biāo)對象實(shí)現(xiàn)了若干接口,spring使用jdk的動態(tài)代理:java.lang.reflect.Proxy類代理
若目標(biāo)對象沒事實(shí)現(xiàn)任何的接口,spring使用CGLIB庫生成目標(biāo)對象的子類
程序中應(yīng)優(yōu)先對接口創(chuàng)建代理,以便于程序的解耦合以及后期的維護(hù)
標(biāo)記為final的方法,不能被代理,因?yàn)闊o法進(jìn)行覆蓋重寫:因?yàn)樗龥]有辦法去重寫父類或者父接口上面的方法
JDK的動態(tài)代理,是針對接口生成子類,接口中的方法不能使用final修飾
CGLIB是針對目標(biāo)類生成子類,因此類或方法不能使用final
Spring只支持方法連接點(diǎn),不提供屬性連接點(diǎn)
一般切面的代碼案例
定義StudentDao接口
publicinterfaceStudentDao{
publicvoidsave();
?
publicvoidfind();
?
publicvoidupdate();
?
publicvoiddelete();
}
接口的實(shí)現(xiàn)類,實(shí)現(xiàn)了接口StudentDao
publicclassStudentDaoImplimplementsStudentDao{
publicvoidsave() {
System.out.println("save執(zhí)行了。。。。。。。");
?? }
?
publicvoidfind() {
System.out.println("find執(zhí)行了。。。。。。。");
?? }
?
publicvoidupdate() {
System.out.println("update執(zhí)行了。。。。。。");
?? }
?
publicvoiddelete() {
System.out.println("delete執(zhí)行了。。。。。。");
?? }
}
定義一個一般切面Advisor
publicclassMyBeforeAdviceimplementsMethodBeforeAdvice{
publicvoidbefore(Methodmethod,Object[]objects,Objecto)throwsThrowable{
System.out.println("前置通知======================");
?? }
}
配置文件中配置
<!--配置目標(biāo)類-->
<beanid="studentDao"class="com.imooc.aop.demo3.StudentDaoImpl"></bean>
?
<!--前置通知類型-->
<beanid="myBeforeAdvice"class="com.imooc.aop.demo3.MyBeforeAdvice"></bean>
?
<!--SpringAOP產(chǎn)生代理對象-->
<beanid="studentDaoProxy"class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置目標(biāo)類-->
<propertyname="target"ref="studentDao"></property>
<!--實(shí)現(xiàn)的接口-->
<propertyname="proxyInterfaces"value="com.imooc.aop.demo3.StudentDao"></property>
<!--采用攔截的名稱-->
<propertyname="interceptorNames"value="myBeforeAdvice"></property>
</bean>
Spring帶有切入點(diǎn)的切面配置
我們需要代理的對象
publicclassCustomerDao{
publicvoidfind(){
System.out.println("查詢用戶...");
?? }
?
publicvoidsave(){
System.out.println("保存用戶...");
?? }
?
publicvoidupdate(){
System.out.println("修改用戶");
?? }
?
publicvoiddelete(){
System.out.println("刪除用戶");
?? }
通知Advice
/*
環(huán)繞通知時最強(qiáng)大的一種通知類型,它可以阻止目標(biāo)方法的執(zhí)行
*/
publicclassMyArroundAdviceimplementsMethodInterceptor{
?
publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{
?
?
System.out.println("環(huán)繞前增強(qiáng)...");
Objectobj=invocation.proceed();//用來執(zhí)行目標(biāo)方法,比如說原來的方法是執(zhí)行保存,這句哈的意思就相當(dāng)于執(zhí)行保存的操作
System.out.println("環(huán)繞后增強(qiáng)...");
?
returnobj;
?? }
配置
<!--配置目標(biāo)類-->
<beanid="customerDao"class="com.imooc.aop.demo4.CustomerDao"></bean>
?
<!--配置通知-->
<beanid="myArroundAdvice"class="com.imooc.aop.demo4.MyArroundAdvice"></bean>
?
<!--一般的切面是使用整個通知來作為切面的,因?yàn)橐獙δ繕?biāo)類某個方法或某些方法進(jìn)行增強(qiáng)就需要配置一個帶有切入點(diǎn)的切面-->
<beanid="myAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<!--pattern中配置正則表達(dá)式:.代表任意字符;*代表任意次數(shù)-->
<propertyname="patterns"value=".*save.*,.*delete.*"></property>
<!--應(yīng)用哪種通知-->
<propertyname="advice"ref="myArroundAdvice"></property>
</bean>
?
<!--配置產(chǎn)生代理-->
<beanid="customerDaoProxy"class="org.springframework.aop.framework.ProxyFactoryBean">
<propertyname="target"ref="customerDao"></property>
<propertyname="proxyTargetClass"value="true"></property>
<propertyname="interceptorNames"value="myAdvisor"></property>
</bean>
</beans>
自動創(chuàng)建代理
BeanNameAutoProxyCreate舉例
基于Bean名稱的自動代理的創(chuàng)建方式,根據(jù)目標(biāo)類的名稱產(chǎn)生代理
先把前幾個例子中的接口,接口實(shí)現(xiàn)類,通知等拷貝過來
publicclassCustomerDao{
publicvoidfind(){
System.out.println("查詢用戶...");
?? }
?
publicvoidsave(){
System.out.println("保存用戶...");
?? }
?
publicvoidupdate(){
System.out.println("修改用戶");
?? }
?
publicvoiddelete(){
System.out.println("刪除用戶");
?? }
}
publicinterfaceStudentDao{
publicvoidsave();
?
publicvoidfind();
?
publicvoidupdate();
?
publicvoiddelete();
}
publicclassStudentDaoImplimplementsStudentDao{
publicvoidsave() {
System.out.println("save執(zhí)行了。。。。。。。");
?? }
?
publicvoidfind() {
System.out.println("find執(zhí)行了。。。。。。。");
?? }
?
publicvoidupdate() {
System.out.println("update執(zhí)行了。。。。。。");
?? }
?
publicvoiddelete() {
System.out.println("delete執(zhí)行了。。。。。。");
?? }
}
publicclassMyBeforeAdviceimplementsMethodBeforeAdvice{
?
publicvoidbefore(Methodmethod,Object[]objects,Objecto)throwsThrowable{
System.out.println("前置通知======================");
?? }
}
publicclassMyArroundAdviceimplementsMethodInterceptor{
?
publicObjectinvoke(MethodInvocationinvocation)throwsThrowable{
?
?
System.out.println("環(huán)繞前增強(qiáng)...");
Objectobj=invocation.proceed();//用來執(zhí)行目標(biāo)方法,比如說原來的方法是執(zhí)行保存,這句哈的意思就相當(dāng)于執(zhí)行保存的操作
System.out.println("環(huán)繞后增強(qiáng)...");
?
returnobj;
?? }
}
配置文件配置
?
<!--配置目標(biāo)類-->
<beanid="studentDao"class="com.imooc.aop.demo5.StudentDaoImpl"></bean>
<beanid="customerDao"class="com.imooc.aop.demo5.CustomerDao"></bean>
?
<!--配置增強(qiáng),Advice-->
<beanid="myArroundAdvice"class="com.imooc.aop.demo5.MyArroundAdvice"></bean>
<beanid="myBedoreAdvice"class="com.imooc.aop.demo5.MyBeforeAdvice"></bean>
?
<!--自動代理-->
<beanclass="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<propertyname="beanNames"value="*Dao"></property>
<propertyname="interceptorNames"value="myBedoreAdvice"></property>
</bean>
?
</beans>
這種自動代理有缺陷,比如說只想增強(qiáng)其中的save方法該怎么做到呢,這是基于Bean名稱的方式又不太合適了
DefalutAdvisorAutoProxyCreator舉例
默認(rèn)的切面的自動代理的方式創(chuàng)建,這種方式可以基于切面的信息自動產(chǎn)生代理
前幾個步驟與上一個方法類似,只是在配置文件中不同
<!--配置目標(biāo)類-->
<beanid="studentDao"class="com.imooc.aop.demo6.StudentDaoImpl"></bean>
<beanid="customerDao"class="com.imooc.aop.demo6.CustomerDao"></bean>
?
<!--配置增強(qiáng),Advice-->
<beanid="myArroundAdvice"class="com.imooc.aop.demo6.MyArroundAdvice"></bean>
<beanid="myBedoreAdvice"class="com.imooc.aop.demo6.MyBeforeAdvice"></bean>
?
<!--配置一個切面-->
<beanid="myAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<propertyname="pattern"value="com\.imooc\.aop\.demo6\.CustomerDao\.save"></property>
<propertyname="advice"ref="myArroundAdvice"></property>
</bean>
?
<beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>
配置了一個切面,因?yàn)槭腔谇忻娴男畔⒆詣赢a(chǎn)生代理
在切面配置中,<property name="pattern" value="com\.imooc\.aop\.demo6\.CustomerDao\.save"></property>;這一步就是根據(jù)類中的方法來增強(qiáng),由于是正則表達(dá)式,所有需要對.進(jìn)行轉(zhuǎn)義\
AspectJ的注解AOP開發(fā)
AspectJ簡介
AspectJ是一個基于Java語言的AOP框架
Spring2.0以后新增了對AspectJ切點(diǎn)表達(dá)式的支持
@AspectJ是AspectJ1.5新增的功能,通過JDK5注解技術(shù),允許直接在Bean類中定義切面
新版本的Spring框架,都建議使用AspectJ方式來開發(fā)AOP
need-to-insert-img
為目標(biāo)類,定義切面類
publicclassPeoductDao{
publicvoidsave(){
System.out.println("保存商品");
?? }
?
publicvoiddelete(){
System.out.println("刪除商品");
?? }
?
publicvoidupdate(){
System.out.println("修改商品");
?? }
?
publicvoidfindOne(){
System.out.println("查詢一個商品");
?
?? }
?
publicvoidfindAll(){
System.out.println("查詢所有的商品");
?? }
/*
切面類
*/
@Aspect
publicclassMyAspect{
@Before(value="execution(* com.imooc.aspectJ.demo1.PeoductDao.save(..))")
publicvoidbefore(){
System.out.println("前置通知");
?? }
<!--開啟AspectJ的注解開發(fā),自動代理-->
<aop:aspectj-autoproxy/>
?
<beanid="peoductDao"class="com.imooc.aspectJ.demo1.PeoductDao"></bean>
?
<!--定義切面-->
<beanclass="com.imooc.aspectJ.demo1.MyAspect"></bean>
詳細(xì)介紹Before前置通知
need-to-insert-img
@AfterReturing 后置通知
@AfterReturning(value="execution(* com.imooc.aspectJ.demo1.PeoductDao.update(..))",returning="re")
publicvoidafterReturing(Objectre){//為什么要用Object,因?yàn)檫@個返回值有可能是任意類型的返回值,所以用Object;
System.out.println("后置通知============="+re);
?? }
//為什么要用Object,因?yàn)檫@個返回值有可能是任意類型的返回值,所以用Object;
@AfterReturing 異常拋出通知
@Around環(huán)繞通知
need-to-insert-img
重點(diǎn):如果不調(diào)用joinPoint.proceed();方法的話,目標(biāo)方法會被攔截,即delete不會執(zhí)行
通過@Pointcut為切點(diǎn)命名
在每個通知內(nèi)定義切點(diǎn),會造成工作量大,不易維護(hù),對于重復(fù)的切點(diǎn),可以使用@Pointcut進(jìn)行定義
切點(diǎn)方法:private void 無參數(shù)方法。方法名為切點(diǎn)名;因?yàn)檫@個方法在類中沒有什么實(shí)際的意義,也不用在別的方法中調(diào)用它,所以定義為private
當(dāng)通知多個切點(diǎn)時,可以使用||進(jìn)行連接
基于AspectJ的xml方式的AOP開發(fā)
通過配置的方式完成AOP的開發(fā)
publicinterfaceCustomerDao{
publicvoidsave();
?
publicvoidfindOne();
?
publicvoidfingAll();
?
publicvoidupdate();
?
publicvoiddelete();
}
publicclassCustomerDaoImplimplementsCustomerDao{
publicvoidsave() {
System.out.println("保存客戶");
?? }
?
publicvoidfindOne() {
System.out.println("查找一個客戶");
?
?? }
?
publicvoidfingAll() {
System.out.println("查找所有的客戶");
?? }
?
publicvoidupdate() {
System.out.println("修改客戶");
?
?? }
?
publicvoiddelete() {
System.out.println("刪除客戶");
?
?? }
<!--xml配置方式完成AOP的開發(fā)-->
<!--配置目標(biāo)類-->
<beanid="customerDao"class="com.imooc.aspectJ.demo2.CustomerDaoImpl"></bean>
need-to-insert-img
need-to-insert-img
need-to-insert-img
JDBC Template