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{@PostConstructpublic void init(){syso("這里是初始化方法");}@PreDestroypublic 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;}//下面為動態代理對象 對原對象的方法加強@Overridepublic 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;}@Overridepublic 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.jarcom.springsource.org.aopalliance-1.0.0.jar* aspectJ開發包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jarspring-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 {@Overridepublic 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;@Testpublic void fun1() {us.save();}}* 結果對比未使用AOP時調用UserService的save方法,結果為 :輸出 "保存"字符串使用了AOP后,字符串輸出結果為:前置通知!這是環繞通知之前的部分!保存另一個后置通知(目標方法運行之后調用,無論是否出現異常都會調用)這是環繞通知之后的部分!后置通知!(如果出現異常則不會調用)<4>注解方式 實現AOP的代碼示例示例需求:對一個UserServiceImpl類 進行AOP增強 其save()方法* UserService類(目標對象)public interface UserService {void save();}public class UserServiceImp implements UserService {@Overridepublic void save() {System.out.println("保存");}}* MyAdvice(通知對象)//注入切面@Aspect public class MyAdvice {//注入切點@Pointcut("execution(* cn.itheima.service.*ServiceImp.*(..))")//空參方法名pc作為 該切點的idpublic 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>
轉載于:https://blog.51cto.com/14008076/2314450