Spring支持用注解配置Bean,更簡便。
上面的組件,是根據實際情況配的。比如寫的一個類,是做業務處理的,那就用注解@Service表示服務層組件,以此類推。將整體分成不同部分。
要在xml加入context命名空間
1 <!-- 指定Spring IOC容器掃描的包 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation"></context:component-scan>
這樣,就表示要自動掃描 基類包的類以及子包中的類。類中有注解,就會被管理
例子:
目錄結構如下,第一個annotation包為要掃描的包,有下面三個子包:controller、repository、service
類里面都是一個簡單的注解和一個方法:
1 //TestObject.java 2 package com.guigu.spring.beans.annotation; 3 4 import org.springframework.stereotype.Component; 5 6 @Component 7 public class TestObject { 8 9 }
1 //UserController.java 2 package com.guigu.spring.beans.annotation.controller; 3 import org.springframework.stereotype.Controller; 4 5 @Controller 6 public class UserController { 7 8 public void execute(){ 9 System.out.println("UserController execute..."); 10 } 11 }
1 //UserRepository.java 2 package com.guigu.spring.beans.annotation.repository; 3 public interface UserRepository { 4 5 void save(); 6 } 7 8 //UserRepositoryImpl.java 繼承 UserRepository 9 package com.guigu.spring.beans.annotation.repository; 10 import org.springframework.stereotype.Repository; 11 12 @Repository("userRepository"); 13 public class UserRepositoryImpl implements UserRepository { 14 15 @Override 16 public void save() { 17 System.out.println("UserRepositoryImpl Save..."); 18 } 19 20 }
寫一個繼承,為了說明注解命名可以更改,這里改成了userRepository,否則是默認的userRepositoryImpl,下面講。
1 //UserService.java 2 package com.guigu.spring.beans.annotation.service; 3 4 import org.springframework.stereotype.Service; 5 6 @Service 7 public class UserService { 8 9 public void add(){ 10 System.out.println("UserService add..."); 11 } 12 }
xml最上面已經配置,最后main函數:
1 package com.guigu.spring.beans.annotation; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 6 import com.guigu.spring.beans.annotation.controller.UserController; 7 import com.guigu.spring.beans.annotation.repository.UserRepository; 8 import com.guigu.spring.beans.annotation.service.UserService; 9 10 public class Main { 11 12 public static void main(String[] args) { 13 14 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 15 TestObject to = (TestObject) ctx.getBean("testObject"); 16 System.out.println(to); 17 UserController userController=(UserController) ctx.getBean("userController"); 18 System.out.println(userController); 19 UserService userservice=(UserService) ctx.getBean("userservice"); 20 System.out.println(userservice); 21 UserRepository userRepository=(UserRepository) ctx.getBean("userRepository"); 22 System.out.println(userRepository); 23 } 24 25 }
輸出如下:說明對象被創建了
xml里面沒有bean,那main函數怎么獲取Bean呢?
就是用最上面圖中藍色字體。Spring默認命名,名字是它的類名第一個字符小寫。如:
UserService.java類中類名是UserService ,獲取bean默認名字就是userService
也可以更改,如上面的UserRepositoryImpl類,用了@Repository("userRepository"),表示bean名字為userRepository
在xml中,有一些屬性和節點:
resource-pattern:只掃描特定文件
context:include-filter: 子節點表示要包含的組件
context:exclude-filter: 子節點表示要排除在外的組件
1 <!-- 可以通過resource-pattern指定掃描的資源 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation" 3 resource-pattern="repository/*.class"> 4 </context:component-scan> 5
這樣,只會掃描repository包下的類,如果main函數中,還要調用其他類,報錯。只能調用repository包下的類。
1 <!-- context:exclude-filter 子節點指定排除哪些指定表達式的組件 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation"> 3 <context:exclude-filter type="annotation" expression="package com.guigu.spring.beans.annotation.repository"/> //type類型后面看 4 </context:component-scan> 5
這表示不掃描repository子包的文件,若main函數中調用它們,會拋異常
1 <!-- context:include-filter 子節點指定包含哪些指定表達式的組件, 該子節點需要use-default-filters配合使用 --> 2 <context:component-scan base-package="package com.guigu.spring.beans.annotation" 3 use-default-filters="false"> 4 <context:include-filter type="annotation" 5 expression="package com.guigu.spring.beans.annotation"/> 6 </context:component-scan>
注意,use-default-filters默認自動掃描全部,要設置成false不自動掃描,才能實現只掃描部分的功能。
<context:include-filter>和<context:exclude-filter>子節點支持多種類型的過濾表達式:
類別 | 示例 | 說明 |
annotation | com.yl.XxxAnnotation | 所有標注了XxxAnnotation的類,該類型采用目標類是否標注了某個注解進行過濾 |
assinable | com.yl.XxxService | 所有繼承或擴展XxxService的類,該類型采用了目標類是否繼承或擴展某個特定類進行過濾 |
aspectj | com.yl.*Service | 所有類名義Service結束的類及繼承或擴展它們的類,該類型采用AspectJ表達式進行過濾 |
regex | com.yl.anno.* | 所有com.yl.anno包下的類。該類型采用正則表達式,根據類的類名進行過濾 |
custom | com.yl.XxxTypeFilter | 采用XxxTypeFilter通過代碼的方式定義過濾原則。該類必須實現org.springframewor |
@Autowired:自動裝配具有兼容類型的單個bean屬性。可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。 通過 @Autowired的使用來代替set方法。(property 屬性通過調用setter方法進行賦值)
意思就是用它,可以代替xml中的<property name="car" ref="car"> 這樣的引用賦值。自動創建bean。
例子:Person類有Car對象,不用 自動裝配
1 //Person類 2 public class Person { 3 private Car car; 4 5 public Car getCar() { 6 return car; 7 } 8 public void setCar(Car car) { 9 this.car = car; 10 } 11 }
1 //Car類 2 public class Car { 3 private String brand; 4 private double price; 5 6 public void setBrand(String brand) { 7 this.brand = brand; 8 } 9 public void setPrice(double price) { 10 this.price = price; 11 } 12 }
xml
1 <bean id="person" class="com.guigu.spring.bean.Person"> 2 <property name="car" ref="car"/> 3 </bean> 4 <bean id="car" class="com.guigu.spring.bean.Car"> 5 <property name="brand" value=" aodi"/> 6 <property name="price" value="200000"/> 7 </bean>
main
1 ApplicationContext context = new ClassPathXmlApplicationContext("autowired.xml"); 2 Person person=(Person)ctx.getBean("person"); 3 System.out.println(person);
這是之前的做法。
@Autowired自動裝配的方法
查了一下,在之前版本的Spring中,要使用@Autowired,要在xml寫上這一行代碼才行
1 <!-- 該 BeanPostProcessor 將自動對標注 @Autowired 的 Bean 進行注入 --> 2 <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
但現在spring4,<context:component-scan>自動注冊AutowiredAnnotationBeanPostProcessor實例,可以使用@Autowired和@Resource、和@Inject注解(一般用@Autowired)
所以,如果使用了<context:component-scan>,就不用額外注冊,不然還是要
1 //Person類 2 public class Person { 3 //@Aotuwired //自動根據xml配置實例car對象 4 private Car car; 5 6 }
1 <bean id="person" class="com.guigu.spring.bean.Person"> 2 //這里就不需要再寫ref="car" 3 </bean> 4 <bean id="car" class="com.guigu.spring.bean.Car"> 5 <property name="brand" value=" aodi"/> 6 <property name="price" value="200000"/> 7 </bean>
結果和不用 @Aotuwired一樣,都可以
還可以寫在setter上
1 //Person類 2 public class Person { 3 private Car car; 4 //@Aotuwired 5 public Car setCar(Car car){ 6 this.car=car; 7 } 8 }
回到注解上面的例子:
1 //UserController.java 2 package com.guigu.spring.beans.annotation.controller; 3 import org.springframework.stereotype.Controller; 4 5 @Controller 6 public class UserController { 7 8 public void execute(){ 9 System.out.println("UserController execute..."); 10 } 11 }
1 // main函數 2 public class Main { 3 4 public static void main(String[] args) { 5 private UserController userController; 6 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 7 userController.execute(); // 報錯
8 }
9 }
在main函數聲明userController然后直接調用它的方法,這樣顯然不行,因為userController都還沒有創建,這時用@Autowired就很簡單
1 // main函數 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 private UserController userController; 7 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 8 userController.execute();//不報錯 9 } 10 }
這樣,就自動配置創建了userController對象,可以直接使用
注意①:@Autowired要想成功配置,得先掃描得到,就是UserController類一定要能被掃描到。
注意②:@Autowired遇到相同兩個類
1 //UserRepository 2 package com.guigu.spring.beans.annotation.repository; 3 public interface UserRepository { 4 5 void save(); 6 } 7 8 //UserRepositoryImpl 繼承 UserRepository 9 package com.guigu.spring.beans.annotation.repository; 10 import org.springframework.stereotype.Repository; 11 12 @Repository("userRepository"); //這里 13 public class UserRepositoryImpl implements UserRepository { 14 15 @Override 16 public void save() { 17 System.out.println("UserRepositoryImpl Save..."); 18 } 19 //UserRepositoryImpl2 繼承 UserRepository 20 @Repository 21 public class UserRepositoryImpl2 implements UserRepository { 22 23 @Override 24 public void save() { 25 System.out.println("UserRepositoryImpl2 Save..."); 26 } 27 }
1 // main函數 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 private UserRepository userRepository ; 7 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 8 userRepository .save(); 9 } 10 }
main函數中有@Autowired,自動創建對象,但UserRepository 類卻有兩個接口,它要去創建哪一個呢?
:默認情況下,若有兩個,去找名字相同的,就是還沒實例的這個userRepository ,若找到和它名字一樣的,上面 @Repository("userRepository"); 寫了名字,那就找它了。
若不是這樣寫@Repository("userRepository");而是 @Repository(),那就報錯了。
注意③:解決②的另一個方法
若@Repository("userRepository");改成@Repository(),main函數會報錯。
改一下main函數
1 // main函數 2 public class Main { 3 4 public static void main(String[] args) { 5 //@Autowired 6 //Qualifier("userRepositoryImpl ") 7 private UserRepository userRepository ; 8 ApplicationContext ctx =new ClassPathXmlApplicationContext("beans-annotation.xml"); 9 userRepository .save(); 10 } 11 }
用Qualifier("userRepositoryImpl ");表示去找userRepositoryImpl 實例,這樣也解決了。