一、注解
注解Annotation,是一種類似注釋的機制,在代碼中添加注解可以在之后某時間使用這些信息。跟注釋不同的是,注釋是給我們看的,java虛擬機不會編譯,注解也是不編譯的,但是我們可以通過反射機制去讀取注解中的信息。注解使用關鍵字@interface,繼承java.lang.annotition.Annotition
1、javaSE中的注解
先舉個例子來回顧一下在javaSE中注解是什么東東,關鍵是兩點,注解的定義與如何通過反射得到注解上面的信息。
1.先定義兩個注解一個是在類上有注解ClassInfo,一個是在方法上有注解為MethodInfo.
ClassInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
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文件以及運行時注解都起作用 @Documented //能生成在幫助文檔中 public @interface ClassInfo { /** * 該注解有兩個String類型的屬性 * @return */ String name() default "" ; String value() default "" ; } |
MethodInfo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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文件以及運行時注解都起作用 @Documented //能生成在幫助文檔中 public @interface MethodInfo { /** * 該注解有兩個String類型的屬性 */ String name() default "" ; String value() default "" ; } |
2.寫一個類AnnotationUse來使用上面定義的注解
1
2
3
4
5
6
7
8
9
|
package com.itheima10.annotation; @ClassInfo (name= "小平果118" ,value= "牛" ) public class AnnotationUse { @MethodInfo (name= "java" ,value= "spring框架很重要" ) public void java(){ } } |
3.編寫測試類AnnotationTest,解析上述兩個注解上面的屬性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
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文件,使開發更加快速。但是,xml文件的使用就是解決修改程序修改源代碼,現在又不去使用xml文件,那么不就違背了開閉原則了么,得確是。不過么,注解也有注解的好,使用注解就不用配置那么多的xml文件啦,最重要的是開發效率高。。
在沒有使用注解時,spring框架的配置文件applicationContext.xml文件中需要配置很多的<bean>標簽,用來聲明類對象。使用注解,則不必在配置文件中添加標簽拉,對應的是在對應類的“注釋”位置添加說明。具體介紹如下:
•1.@Resource 對象間關系的組合,默認采用的是按名稱方式進行裝配,如果根據名稱查找不到關聯的對象,那么會再采用按類型繼續查找。如果沒有指定name屬性,
• 當注解標注在字段上,即默認取字段的名稱作為bean名稱尋找依賴對象
• 當注解標注在屬性的setter方法上,即默認取屬性名作為bean名稱尋找依賴對象。
• 注意:如果沒有指定name屬性,并且按照默認的名稱找不到依賴對象時, @Resource注解會回退到按類型裝配。但一旦指定了name屬性,就只能按名稱裝配了。
•2. @Autowired
@Autowired 默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean才會按類型裝配。 解是按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,如果允許null值,可以設置它required屬性為false。
•3、 @Qualifier
如果我們想使用按名稱裝配,可以結合@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標簽
<context:annotation-config></context:annotation-config>
實例演示:
編寫一個Person類,其中有一個student屬性,以及一個say()方法,代碼如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
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//按照類型進行匹配 * * @Autowired//按照類型進行匹配 @Qualifier("student") * */ public class Person { @Resource (name= "student" ) private Student student; public void say(){ this .student.say(); } } |
Student類代碼如下
1
2
3
4
5
6
7
|
package com.itheima10.spring.di.annotation; public class Student { public void say(){ System.out.println( "student" ); } } |
配置applicationContext.xml文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<? 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" --> <!-- 啟動了以來注入的注解解析器 --> < context:annotation-config ></ context:annotation-config > </ beans > |
編寫測試類AnnotationTest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.itheima10.spring.di.annotation; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * 原理: * 1、啟動spring容器 * 2、把person和student兩個bean實例化 * 3、當spring容器解析到 * <context:annotation-config></context:annotation-config> * 就會啟動依賴注入的注解解析器 * 4、spring容器會在納入spring管理的bean的范圍內查找,看這些類的哪些屬性上加有@Resource注解 * 5、如果某一個屬性上加有@Resource注解 * 會查看該注解的name屬性的值是否為"" * 如果為"",則會把該注解所在的屬性的名稱和spring容器中的id的值作匹配,如果匹配成功,則賦值 * 如果匹配不成功,則按照類型進行匹配,匹配成功則賦值 * 如果再匹配不成功,則報錯 * 如果不為"",則把該注解的name屬性的值和spring容器中id的值作匹配,如果匹配成功,則賦值 * 如果匹配不成功,則直接報錯 * 說明: 注解只能作用于引用類型 xml與注解的對比 xml的效率比較高,書寫比較麻煩 注解的書寫比較簡單,效率比較低 * */ public class AnnotationTest { @Test public void testAnnotation(){ ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" ); Person person = (Person)context.getBean( "person" ); person.say(); } } |
如果使用注解,就不需要在配置文件中裝載person和student了,這樣就可以簡化配置文件的編寫。
3、 掃描
前面的例子我們都是使用XML的bean定義來配置組件。在一個稍大的項目中,通常會有上百個組件,如果這些組件采用xml的bean定義來配置,顯然會增加配置文件的體積,查找及維護起來也不太方便。spring2.5為我們引入了組件自動掃描機制,它可以在類路徑底下尋找標注了@Component、@Service、@Controller、@Repository注解的類,并把這些類納入進spring容器中管理。它的作用和在xml文件中使用bean節點配置組件是一樣的。要使用自動掃描機制,我們需要打開以下配置信息:
1、引入context命名空間
在xml配置文件中添加context:component-scan標簽
其中base-package為需要掃描的包(含子包)。
實例:
將上述實例用掃描的方式書寫如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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只需配置一句話
1
2
3
4
5
6
|
<!-- component 組件 把一個類放入到spring容器中,該類就稱為組件 在base- package 指定的包及子包下掃描 --> <context:component-scan base- package = "com.itheima10.spring.scan" ></context:component-scan> |
編寫測試類AnnotationTest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/** * 原理 * 1、啟動spring容器 * 2、spring容器解析 * <context:component-scan base-package="com.itheima10.spring.scan"> </context:component-scan> 3、在base-package指定的包及子包中掃描,看哪些類上面是否含有@Component注解 4、如果有該注解 @Component public class Person { } ==等價于 <bean id="person" class="..Person"> @Component("aa") public class Person { } ==等價于 <bean id="aa" class="..Person"> 5、按照@Resource的解析步驟執行 說明: 整個過程掃描兩次,效率越來越低,書寫越來越簡單 * * */ public class AnnotationTest { @Test public void testAnnotation(){ ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml" ); Person person = (Person)context.getBean( "person" ); person.say(); } } |
實例再現
我們將Item51中最后的文檔管理系統用注解的方式改一下,Document接口不變,有read和write方法,實現類分別如下ExcelDocument ,PDFDocument ,WordDocument 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@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
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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>
編寫測試類DocumentTest
1
2
3
4
5
6
7
8
9
|
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用于標注業務層組件、服務層注解
@Controller用于標注控制層組件(如struts中的action)、控制層注解
@Repository用于標注數據訪問組件,即DAO組件。持久層注解
而@Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。
實例重現–MVC案例
我們再次回顧Item51中的MVC案例,分別將PersonDaoImpl ,PersonAction ,PersonServiceImpl 的Dao,Service,Action層加上注解有
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
@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(); } } |
編寫測試MVCTest
1
2
3
4
5
6
7
8
9
|
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: 如果設置為true,表示定義的bean是抽象的,告訴spring不要實例化這個bean;
問題:必須是抽象類么?可以不是抽象類么?
(2)parent: 指明bean的id,對bean的作用,相當于extends對于java類的作用;
場景:有三個Bean:
1
2
3
4
5
6
7
8
9
|
<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
1
2
3
|
<bean id = "BaseBean" class = "……TestBean" > <property name= "sex" value= "male" /> </bean> |
定義子Bean
1
2
3
4
5
|
<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. 屬性繼承
幾個不同Bean之間存在相同的屬性,可以抽離出來
場景:
1
2
3
4
5
6
7
|
<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) 抽取公共屬性
1
2
3
|
<bean id = "baseSex" abstract = "true" > <property name= "sex" value= "male" /> </bean> |
(2)bean修改
1
2
3
4
|
<bean id = "bean1" class = "……ATestBean" parent= "baseSex" > <property name= "task" ref= "task" /> </bean> <bean id = "bean2" class = "……BTestBean" parent= "baseSex" /> |
這里bean同時有parent和class屬性,其中parent指向的baseSex,就是為了讓不同Bean之間共享相同的屬性值;在TransactionProxyFactoryBean聲明業務時,Bean屬性繼承能夠明顯的減少冗余的xml配置。
基于注解的繼承無需要parent屬性。
最后上一張小小的總結圖吧
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/i10630226/article/details/50518369