JavaWeb Spring注解Annotation深入學(xué)習(xí)
一、注解
注解Annotation,是一種類似注釋的機(jī)制,在代碼中添加注解可以在之后某時(shí)間使用這些信息。跟注釋不同的是,注釋是給我們看的,java虛擬機(jī)不會(huì)編譯,注解也是不編譯的,但是我們可以通過(guò)反射機(jī)制去讀取注解中的信息。注解使用關(guān)鍵字@interface,繼承java.lang.annotition.Annotition
1、javaSE中的注解
先舉個(gè)例子來(lái)回顧一下在javaSE中注解是什么東東,關(guān)鍵是兩點(diǎn),注解的定義與如何通過(guò)反射得到注解上面的信息。
1.先定義兩個(gè)注解一個(gè)是在類上有注解ClassInfo,一個(gè)是在方法上有注解為MethodInfo.
ClassInfo
package com.itheima10.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) //該注解可以用于類上
@Retention(RetentionPolicy.RUNTIME) //在java,class文件以及運(yùn)行時(shí)注解都起作用
@Documented //能生成在幫助文檔中
public @interface ClassInfo {
/**
* 該注解有兩個(gè)String類型的屬性
* @return
*/
String name() default "";
String value() default "";
}
MethodInfo
package com.itheima10.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) //該注解可以用于方法上
@Retention(RetentionPolicy.RUNTIME) //在java,class文件以及運(yùn)行時(shí)注解都起作用
@Documented //能生成在幫助文檔中
public @interface MethodInfo {
/**
* 該注解有兩個(gè)String類型的屬性
*/
String name() default "";
String value() default "";
}
2.寫一個(gè)類AnnotationUse來(lái)使用上面定義的注解
package com.itheima10.annotation;
@ClassInfo(name="小平果118",value="牛")
public class AnnotationUse {
@MethodInfo(name="java",value="spring框架很重要")
public void java(){
}
}
3.編寫測(cè)試類AnnotationTest,解析上述兩個(gè)注解上面的屬性
package com.itheima10.annotation;
import java.lang.reflect.Method;
import org.junit.Test;
public class AnnotationTest {
public static void test(){
/**
* 如果解析類的注解,先得到Class
* 如果解析方法的注解,先得到method
*/
Class class1 = Itheima10.class;
//判斷類上面是否有ClassInfo注解
if(class1.isAnnotationPresent(ClassInfo.class)){
//得到類上面的注解
ClassInfo classInfo = (ClassInfo)class1.getAnnotation(ClassInfo.class);
System.out.println(classInfo.value());
System.out.println(classInfo.name());
}
Method[] methods = class1.getMethods();
for (Method method : methods) {
//正在遍歷的方法上面是否存在MethodInfo注解
if(method.isAnnotationPresent(MethodInfo.class)){
MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
System.out.println(methodInfo.name());
System.out.println(methodInfo.value());
}
}
}
@Test
public void test(){
AnnotationTest.test();
}
}
2、spring中的注解
spring框架為我們提供了注解功能。
使用注解編程,主要是為了替代xml文件,使開(kāi)發(fā)更加快速。但是,xml文件的使用就是解決修改程序修改源代碼,現(xiàn)在又不去使用xml文件,那么不就違背了開(kāi)閉原則了么,得確是。不過(guò)么,注解也有注解的好,使用注解就不用配置那么多的xml文件啦,最重要的是開(kāi)發(fā)效率高。。
在沒(méi)有使用注解時(shí),spring框架的配置文件applicationContext.xml文件中需要配置很多的<bean>標(biāo)簽,用來(lái)聲明類對(duì)象。使用注解,則不必在配置文件中添加標(biāo)簽拉,對(duì)應(yīng)的是在對(duì)應(yīng)類的“注釋”位置添加說(shuō)明。具體介紹如下:
•1.@Resource 對(duì)象間關(guān)系的組合,默認(rèn)采用的是按名稱方式進(jìn)行裝配,如果根據(jù)名稱查找不到關(guān)聯(lián)的對(duì)象,那么會(huì)再采用按類型繼續(xù)查找。如果沒(méi)有指定name屬性,
• 當(dāng)注解標(biāo)注在字段上,即默認(rèn)取字段的名稱作為bean名稱尋找依賴對(duì)象
• 當(dāng)注解標(biāo)注在屬性的setter方法上,即默認(rèn)取屬性名作為bean名稱尋找依賴對(duì)象。

• 注意:如果沒(méi)有指定name屬性,并且按照默認(rèn)的名稱找不到依賴對(duì)象時(shí), @Resource注解會(huì)回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。
•2. @Autowired
@Autowired 默認(rèn)按類型裝配,@Resource默認(rèn)按名稱裝配,當(dāng)找不到與名稱匹配的bean才會(huì)按類型裝配。 解是按類型裝配依賴對(duì)象,默認(rèn)情況下它要求依賴對(duì)象必須存在,如果允許null值,可以設(shè)置它required屬性為false。
•3、 @Qualifier
如果我們想使用按名稱裝配,可以結(jié)合@Qualifier注解一起使用。
1、使用注解,需要在配置文件中增加命名空間和約束文件步驟:
引入context命名空間
<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"
...
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
2、 在配置文件中加入context:annotation-config標(biāo)簽
<context:annotation-config></context:annotation-config>
實(shí)例演示:
編寫一個(gè)Person類,其中有一個(gè)student屬性,以及一個(gè)say()方法,代碼如下
package com.itheima10.spring.di.annotation;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* @Autowired//按照類型進(jìn)行匹配
*
* @Autowired//按照類型進(jìn)行匹配
@Qualifier("student")
*
*/
public class Person {
@Resource(name="student")
private Student student;
public void say(){
this.student.say();
}
}
Student類代碼如下
package com.itheima10.spring.di.annotation;
public class Student {
public void say(){
System.out.println("student");
}
}
配置applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- 把person和student放入到spring容器中 --> <bean id="person" class="com.itheima10.spring.di.annotation.Person"></bean> <bean id="student" class="com.itheima10.spring.di.annotation.Student"></bean> <!-- 引入context命名空間 xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" --> <!-- 啟動(dòng)了以來(lái)注入的注解解析器 --> <context:annotation-config></context:annotation-config> </beans>
編寫測(cè)試類AnnotationTest
package com.itheima10.spring.di.annotation;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 原理:
* 1、啟動(dòng)spring容器
* 2、把person和student兩個(gè)bean實(shí)例化
* 3、當(dāng)spring容器解析到
* <context:annotation-config></context:annotation-config>
* 就會(huì)啟動(dòng)依賴注入的注解解析器
* 4、spring容器會(huì)在納入spring管理的bean的范圍內(nèi)查找,看這些類的哪些屬性上加有@Resource注解
* 5、如果某一個(gè)屬性上加有@Resource注解
* 會(huì)查看該注解的name屬性的值是否為""
* 如果為"",則會(huì)把該注解所在的屬性的名稱和spring容器中的id的值作匹配,如果匹配成功,則賦值
* 如果匹配不成功,則按照類型進(jìn)行匹配,匹配成功則賦值
* 如果再匹配不成功,則報(bào)錯(cuò)
* 如果不為"",則把該注解的name屬性的值和spring容器中id的值作匹配,如果匹配成功,則賦值
* 如果匹配不成功,則直接報(bào)錯(cuò)
*
說(shuō)明:
注解只能作用于引用類型
xml與注解的對(duì)比
xml的效率比較高,書寫比較麻煩
注解的書寫比較簡(jiǎn)單,效率比較低
*
*/
public class AnnotationTest {
@Test
public void testAnnotation(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person)context.getBean("person");
person.say();
}
}
如果使用注解,就不需要在配置文件中裝載person和student了,這樣就可以簡(jiǎn)化配置文件的編寫。
3、 掃描
前面的例子我們都是使用XML的bean定義來(lái)配置組件。在一個(gè)稍大的項(xiàng)目中,通常會(huì)有上百個(gè)組件,如果這些組件采用xml的bean定義來(lái)配置,顯然會(huì)增加配置文件的體積,查找及維護(hù)起來(lái)也不太方便。spring2.5為我們引入了組件自動(dòng)掃描機(jī)制,它可以在類路徑底下尋找標(biāo)注了@Component、@Service、@Controller、@Repository注解的類,并把這些類納入進(jìn)spring容器中管理。它的作用和在xml文件中使用bean節(jié)點(diǎn)配置組件是一樣的。要使用自動(dòng)掃描機(jī)制,我們需要打開(kāi)以下配置信息:
1、引入context命名空間
在xml配置文件中添加context:component-scan標(biāo)簽
其中base-package為需要掃描的包(含子包)。
實(shí)例:
將上述實(shí)例用掃描的方式書寫如下
@Component
public class Person {
@Resource(name="student")
private Student student;
public void say(){
this.student.say();
}
}
@Component
public class Student {
public void say(){
System.out.println("student");
}
}
applicationContext.xml只需配置一句話
<!-- component 組件 把一個(gè)類放入到spring容器中,該類就稱為組件 在base-package指定的包及子包下掃描 --> <context:component-scan base-package="com.itheima10.spring.scan"></context:component-scan>
編寫測(cè)試類AnnotationTest
/**
* 原理
* 1、啟動(dòng)spring容器
* 2、spring容器解析
* <context:component-scan base-package="com.itheima10.spring.scan">
</context:component-scan>
3、在base-package指定的包及子包中掃描,看哪些類上面是否含有@Component注解
4、如果有該注解
@Component
public class Person {
}
==等價(jià)于
<bean id="person" class="..Person">
@Component("aa")
public class Person {
}
==等價(jià)于
<bean id="aa" class="..Person">
5、按照@Resource的解析步驟執(zhí)行
說(shuō)明:
整個(gè)過(guò)程掃描兩次,效率越來(lái)越低,書寫越來(lái)越簡(jiǎn)單
*
*
*/
public class AnnotationTest {
@Test
public void testAnnotation(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person)context.getBean("person");
person.say();
}
}
實(shí)例再現(xiàn)
我們將Item51中最后的文檔管理系統(tǒng)用注解的方式改一下,Document接口不變,有read和write方法,實(shí)現(xiàn)類分別如下ExcelDocument ,PDFDocument ,WordDocument 。
@Component("excelDocument")
public class ExcelDocument implements Document{
public void read() {
System.out.println("excel read");
}
public void write() {
System.out.println("excel write");
}
}
@Component("pdfDocument")
public class PDFDocument implements Document{
public void read() {
System.out.println("pdf read");
}
public void write() {
System.out.println("pdf write");
}
}
@Component("wordDocument")
public class WordDocument implements Document{
public void read() {
System.out.println("word read");
}
public void write() {
System.out.println("word write");
}
}
DocumentManager
@Component("documentManager")
public class DocumentManager {
@Resource(name="excelDocument")
private Document document;
public void read(){
this.document.read();
}
public void write(){
this.document.write();
}
}
配置文件
<context:component-scan base-package="com.itheima10.spring.iocdi.document">
</context:component-scan>
編寫測(cè)試類DocumentTest
public class DocumentTest {
@Test
public void testDocument(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DocumentManager documentManager = (DocumentManager)context.getBean("documentManager");
documentManager.read();
documentManager.write();
}
}
2、其他注解功能介紹
@Service用于標(biāo)注業(yè)務(wù)層組件、服務(wù)層注解
@Controller用于標(biāo)注控制層組件(如struts中的action)、控制層注解
@Repository用于標(biāo)注數(shù)據(jù)訪問(wèn)組件,即DAO組件。持久層注解
而@Component泛指組件,當(dāng)組件不好歸類的時(shí)候,我們可以使用這個(gè)注解進(jìn)行標(biāo)注。
實(shí)例重現(xiàn)–MVC案例
我們?cè)俅位仡橧tem51中的MVC案例,分別將PersonDaoImpl ,PersonAction ,PersonServiceImpl 的Dao,Service,Action層加上注解有
@Repository("personDao")
public class PersonDaoImpl implements PersonDao {
@Override
public void savePerson() {
System.out.println(" save person");
}
}
@Service("personService")
public class PersonServiceImpl implements PersonService{
@Resource(name="personDao")
private PersonDao personDao;
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
@Override
public void savePerson() {
this.personDao.savePerson();
}
}
@Controller("personAction")
public class PersonAction {
@Resource(name="personService")
private PersonService personService;
public void setPersonService(PersonService personService) {
this.personService = personService;
}
public void savePerson(){
this.personService.savePerson();
}
}
編寫測(cè)試MVCTest
public class MVCTest {
@Test
public void testMVC(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
PersonAction personAction = (PersonAction)context.getBean("personAction");
personAction.savePerson();
}
}
4. spring中的繼承
Spring支持繼承,可以分為類繼承和屬性繼承
1. 類繼承
Spring屬性:
(1)abstract: 如果設(shè)置為true,表示定義的bean是抽象的,告訴spring不要實(shí)例化這個(gè)bean;
問(wèn)題:必須是抽象類么?可以不是抽象類么?
(2)parent: 指明bean的id,對(duì)bean的作用,相當(dāng)于extends對(duì)于java類的作用;
場(chǎng)景:有三個(gè)Bean:
<bean id = "bean1" class = "……TestBean"> <property name="sex" value="male"/> </bean> <bean id = "bean2" class = "……TestBean"> <property name="sex" value="male"/> </bean> <bean id = "bean3" class = "……TestBean"> <property name="sex" value="female"/> </bean>
修改:定義spring 父bean
<bean id ="BaseBean" class ="……TestBean"> <property name="sex" value="male"/> </bean>
定義子Bean
<bean id ="bean1" parent = "BaseBean"/> 繼承父Bean的屬性 <bean id ="bean2" parent = "BaseBean"/> <bean id ="bean3" parent = "BaseBean"> 覆蓋父Bean的屬性 <property name="sex" value="female"/> </bean>
子bean可以繼承父Bean的屬性,也可以覆蓋父Bean的屬性
2. 屬性繼承
幾個(gè)不同Bean之間存在相同的屬性,可以抽離出來(lái)
場(chǎng)景:
<bean id = "bean1" class = "……ATestBean"> <property name="sex" value="male"/> <property name="task" ref="task"/> </bean> <bean id = "bean2" class = "……BTestBean"> <property name="sex" value="male"/> </bean>
修改:(1) 抽取公共屬性
<bean id = "baseSex" abstract="true"> <property name="sex" value="male"/> </bean>
(2)bean修改
<bean id = "bean1" class = "……ATestBean" parent="baseSex"> <property name="task" ref="task"/> </bean> <bean id = "bean2" class = "……BTestBean" parent="baseSex"/>
這里bean同時(shí)有parent和class屬性,其中parent指向的baseSex,就是為了讓不同Bean之間共享相同的屬性值;在TransactionProxyFactoryBean聲明業(yè)務(wù)時(shí),Bean屬性繼承能夠明顯的減少冗余的xml配置。
基于注解的繼承無(wú)需要parent屬性。
最后上一張小小的總結(jié)圖吧

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java實(shí)現(xiàn)系統(tǒng)捕獲異常發(fā)送郵件案例
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)系統(tǒng)捕獲異常發(fā)送郵件案例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11
新手場(chǎng)景Java線程相關(guān)問(wèn)題及解決方案
這篇文章主要介紹了新手場(chǎng)景Java線程相關(guān)問(wèn)題及解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
劍指Offer之Java算法習(xí)題精講二叉樹(shù)專題篇上
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(41)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07
解決運(yùn)行jar包出錯(cuò):ClassNotFoundException問(wèn)題
這篇文章主要介紹了解決運(yùn)行jar包出錯(cuò):ClassNotFoundException問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Sharding Jdbc批量操作引發(fā)fullGC解決
這篇文章主要為大家介紹了Sharding Jdbc批量操作引發(fā)fullGC解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11

