Spring框架知識複習之二
阿新 • • 發佈:2018-11-08
Spring使用註解對Bean進行管理
1 使用註解需配置aop相關xsd檔案的約束和名稱空間
xsd檔名為:spring-aop-4.2.xsd
2 註解元件掃描配置
示例如下:base-package屬性 設定掃描指定包下的所有子孫包
<context:component-scan base-package="cn.itma.bean"></context:component-scan>
3 spring管理bean的常用註解
<1>作用在類上的 用於建立物件的 @Component元件註解 的三個衍生註解(功能一致)
* @Controller :WEB層 * @Service:業務層 * @Repository:持久層 示例如下 註解書寫: package xxx.yyy.test; @Component("user") @Scope(scopeName="prototype") public class User{ } 對應的xml配置書寫: <bean name="user" class="xxx.yyy.test.User" scope="prototype"/>
<2> 用於屬性注入的註解 (使用註解注入的方式,可以不用提供set方法)
* @Value:用於注入普通型別 * @Autowired:自動裝配(預設按型別進行裝配) 存在的問題: 如果匹配多個型別一致的物件,將無法選擇具體注入哪一個物件, 需要加一個註解輔助,宣告它要注入哪一個Car物件 * @Qualifier:強制按照名稱進行注入。 存在的問題: 如果存在多個名稱一致的,型別不一致的物件,將無法準確匹配到。 * @Resource:相當於@Autowired和@Qualifier一起使用 示例如下 註解書寫: public class User{ @Value("flower") private String name; public String getName() {return name;} public void setName(String name) {this.name = name;} @Resource(name="car") private Car c; } 對應的xml配置書寫: <bean name="user" class="xxx.yyy.User"> <property name="name" value="flower"/> <property name="car" ref="car"></property> </bean> <bean name="car" class="xx.bean.Car"> <property name="name" value="dd"></property> <property name="color" value="black"></property> </bean>
<3>Spring整合junit測試的 註解
* 匯入的包為:spring-test-4.2.4.RELEASE.jar
* @RunWith(SpringJUnit4Cla***unner.class) --幫我們建立容器
* @ContextConfiguration("classpath:applicationContext.xml") --指定建立容器使用哪個配置檔案
<4>設定Bean作用範圍的註解
@Scope:
* singleton:單例
* prototype: 多例
<4>設定Bean生命週期的註解
@PostConstruct:相當於init-method @PreDestroy:相當於destroy-method 示例如下 註解書寫: public class User{ @PostConstruct public void init(){ syso("這裡是初始化方法"); } @PreDestroy public void destroy(){ syso("這裡是銷燬方法") } } 對應的xml配置書寫: <bean name="user" class="xxx.yyy.User" init-method="init" destroy-method="destroy"> </bean>
4 spring管理bean的xml方式與註解方式對比
xml配置 註解配置
(1)bean的建立和定義 <bean id="" class=""/> @Component(三個衍生:Controller,Service,Repository)
(2)bean名稱的指定 通過id或name指定 @Component("person")
(3)bean中引數的注入 通過<property>或p名稱空間 @Autowired(按型別注入)或@QUalifier(按名稱注入)或Resource(兩者相加)
(4)bean生命週期和 通過設定Scope屬性,包括: singleton和prototype @Scope(scopeName="singleton")作用範圍的設定
總結:
xml結構清晰,註解開發方便,所以實際開發中有一種xml和註解開發(Bean有XML配置,但使用的屬性用註解注入)。
5 Spring和AOP面向切面程式設計
1 AOP概述
AOP(aspect oriented Programming面向切面程式設計),AOP是OOP(面向物件程式設計)的延續,
也是Spring框架的一個重要內容,spring利用AOP可以對業務邏輯各個部分進行隔離,
降低業務邏輯之間的耦合性,提供程式的重用性和開發效率。
2 Spring中AOP的主要功能
在不修改原始碼的基礎上,對程式進行增強,可進行許可權校驗,日誌記錄,效能監控,事務控制。
3 Spring的AOP底層實現
兩種代理機制:
* JDK的動態代理:針對實現了介面的類產生代理
示例:
//手動實現動態代理--演示(針對的是代理物件和被代理物件的實現同一介面)
public class UserServiceProxyFactory implements InvocationHandler {
private UserService us;
public UserServiceProxyFactory() {super();}
public UserServiceProxyFactory(UserService us) {super();this.us = us;}
public UserService getUserServiceProxy() {
//生成 UserService動態代理物件
UserService usProxy=(UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
UserServiceImp.class.getInterfaces(),
this);
//返回
return usProxy;
}
//下面為動態代理物件 對原物件的方法加強
@Override
public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
System.out.println("開啟事務");
Object invoke = method.invoke(us,arg2);
System.out.println("提交事務");
return invoke;
}
}
* Cglib的動態代理:針對沒有實現的介面的類產生代理,應用的是底層位元組碼增強技術,生成當前類的子類物件。
示例:
//通過第三方實現 代理技術--cglib技術(針對的是代理物件和被代理物件的繼承關係)
public class UserServiceProxyFactory2 implements MethodInterceptor{
private UserService us;
public UserServiceProxyFactory2(UserService us) {super();this.us = us;}
public UserServiceProxyFactory2() {super();}
public UserService getUserServiceProxy() {
Enhancer en=new Enhancer(); //幫我們生成代理的物件
en.setSuperclass(UserServiceImp.class); //設定對誰進行代理
en.setCallback(this); //指定代理物件 要增強什麼功能(代理要做什麼)
UserService us = (UserService) en.create(); //建立代理物件
return us;
}
@Override
public Object intercept(Object proxyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
//開啟事務
System.out.println("開啟事務");
//呼叫原有方法
Object returnValue = methodProxy.invokeSuper(proxyobj,arg);
//提交事務
System.out.println("提交事務");
return returnValue;
}
}
4 Spring基於AspectJ的AOP開發
(1)Spring的AOP開放相關術語:
<1>Joinpoint(連線點):所謂連線點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支援方法型別的連線點.
<2>Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義
& execution()切入點表示式的基本語法:
* 基本格式:execution( [方法訪問修飾符] 方法返回值 全類名.方法名(方法引數))
* 配置方法名的不同形式:
public void cn.itheima.service.UserServiceImp.save() 簡單形式
void cn.itheima.service.UserServiceImp.save() public可省略
* cn.itheima.service.UserServiceImp.save() *代表任意的返回值型別
* cn.itheima.service.UserServiceImp.*() *()代表該目標物件下的所有方法
* cn.itheima.service.UserServiceImp.*(..) *(..)對方法引數不作任何要求(空參和實參都行)
//下面為開發常用形式
* cn.itheima.service.*ServiceImp.*(..) *ServiceImp代表名稱包含 ServiceImp的目標物件(是開發的標準形式)
* cn.itheima.service..*ServiceImp.*(..) ..*ServiceImp 代表 在包括service下的子孫包中的 名稱包含 ServiceImp的目標物件
& 配置AOP切入點示例:
<aop:config>
id屬性:為切入點命名
<aop:pointcut expression="execution(* cn.ith.service.*ServiceImp.*(..))" id="pc"/>
</aop:config>
<3>Advice(通知/增強):
所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.
通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
有一種特殊的通知:Introduction(引介)
不修改類程式碼的前提下, Introduction可以在執行期為類動態地新增一些方法或Field.
通知型別詳解
前置通知(before):在目標方法執行 之前.
後置通知(afterReturning) :在目標方法執行 之後,如果出現異常則不會呼叫
環繞通知(around) :在目標方法執行 前和後
異常丟擲通知(afterException):在目標方法執行 出現異常的時候 執行
最終通知(after) :無論目標方法是否出現異常 最終通知都會 執行 .
<4>Aspect(切面): 是切入點和通知(引介)的結合
配置切面:
<!-- 屬性ref:要關聯的 通知 名稱 -->
<!--2.配置通知物件(目標物件的增強版)-->
<bean name="myAdvice" class="cn.itheima.d_aspect.MyAdvice"></bean>
<aop:aspect ref="myAdvice">
<!-- method屬性:設定方法名 pointcut-ref:設定要關聯的 切點名稱-->
<!--指定名為before為前置通知-->
<aop:before method="before" pointcut-ref="pc"/>
<!--指定名為afterReturning為後置通知(出現異常不會呼叫) -->
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<!--指定名為around為環繞通知 -->
<aop:around method="around" pointcut-ref="pc"/>
<!--指定名為afterException為異常攔截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!--指定名為after為後置通知(是否出現異常都會呼叫) -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
<5>Target(目標物件):代理的目標物件
<6>Weaving(織入):
是指把增強應用到目標物件來建立新的代理物件的過程。
spring採用動態代理織入,而AspectJ採用編譯期織入和類裝在期織入.
AspectJ是一個面向切面的框架,它定義了AOP語法,擴充套件了Java語言。
<7>Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類
(2)Spring使用AspectJ進行AOP開發
<1>要匯入相關的jar包,如下
* spring傳統aop開發包:
spring-aop-4.2.4.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
* aspectJ開發包:
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aspects-4.2.4.RELEASE.jar
<2>匯入aop約束
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<3>配置xml方式實現AOP的程式碼示例
示例需求:對一個UserServiceImpl類 進行AOP增強 其save()方法
* UserService類(目標物件)
public interface UserService {void save();}
public class UserServiceImp implements UserService {
@Override
public void save() {
System.out.println("儲存");
}
}
* MyAdvice(通知物件)
public class MyAdvice {
public void before() {
System.out.println("前置通知!");
}
public void afterReturning() {
System.out.println("後置通知!(如果出現異常則不會呼叫)");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("這是環繞通知之前的部分!");
Object proceed = pjp.proceed(); //呼叫目標方法
System.out.println("這是環繞通知之後的部分!");
return proceed;
}
public void afterException() {
System.out.println("出現異常了!");
}
public void after() {
System.out.println("另一個後置通知(目標方法執行之後呼叫,無論是否出現異常都會呼叫)");
}
}
* AOP相關配置
<!--1.配置目標物件 -->
<bean name="userService" class="cn.ith.service.UserServiceImp"></bean>
<!--2.配置通知物件(目標物件的增強版)-->
<bean name="myAdvice" class="cn.it_aspect.MyAdvice"></bean>
<!--3.配置將通知織入目標物件 -->
<aop:config>
配置切入點
<aop:pointcut expression="execution(* cn.itheima.service.*ServiceImp.*(..))" id="pc"/>
配置切面(切點+通知)
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
* 測試類程式碼
@RunWith(SpringJUnit4Cla***unner.class)
@ContextConfiguration("classpath:cn/itheima/d_aspect/applicationContext.xml")
public class Demo {
//將名為 userService的目標物件注入到 us成員變數中
@Resource(name="userService")
private UserService us;
@Test
public void fun1() {
us.save();
}
}
* 結果對比
未使用AOP時呼叫UserService的save方法,結果為 :輸出 "儲存"字串
使用了AOP後,字串輸出結果為:
前置通知!
這是環繞通知之前的部分!
儲存
另一個後置通知(目標方法執行之後呼叫,無論是否出現異常都會呼叫)
這是環繞通知之後的部分!
後置通知!(如果出現異常則不會呼叫)
<4>註解方式 實現AOP的程式碼示例
示例需求:對一個UserServiceImpl類 進行AOP增強 其save()方法
* UserService類(目標物件)
public interface UserService {void save();}
public class UserServiceImp implements UserService {
@Override
public void save() {
System.out.println("儲存");
}
}
* MyAdvice(通知物件)
//注入切面
@Aspect
public class MyAdvice {
//注入切點
@Pointcut("execution(* cn.itheima.service.*ServiceImp.*(..))")
//空參方法名pc作為 該切點的id
public void pc(){}
//注入前置通知,並指定切入點
//@Before("execution(* cn.itheima.service.*ServiceImp.*(..))")
@Before("MyAdvice.pc()") //簡寫
public void before() {
System.out.println("前置通知!");
}
//注入後置通知,並指定切入點
@AfterReturning("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void afterReturning() {
System.out.println("後置通知!(如果出現異常則不會呼叫)");
}
//注入環繞通知,並指定切入點
@Around("execution(* cn.itheima.service.*ServiceImp.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("這是環繞通知之前的部分!");
Object proceed = pjp.proceed(); //呼叫目標方法
System.out.println("這是環繞通知之後的部分!");
return proceed;
}
//注入異常攔截通知,並指定切入點
@AfterThrowing("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void afterException() {
System.out.println("出現異常了!");
}
//注入後置通知,並指定切入點
@After("execution(* cn.itheima.service.*ServiceImp.*(..))")
public void after() {
System.out.println("另一個後置通知(目標方法執行之後呼叫,無論是否出現異常都會呼叫)");
}
}
* AOP內的配置內容
<!--1.配置目標物件 -->
<bean name="userService" class="cn.itma.service.UserServiceImp"></bean>
<!--2.配置通知物件 -->
<bean name="myAdvice" class="cn.ithnotationAop.MyAdvice"></bean>
<!-- 開啟使用註解完成織入 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>