A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container. Otherwise, a bean is simply one of many objects in your application.java
bean是由Spring IoC容器實例化、裝配和管理的對象,不然,bean只是應用程序中的衆多對象之一。mysql
bean及其之間的依賴關係反映在容器使用的配置元數據中。web
咱們已經瞭解,Spring IoC容器可以幫咱們操做bean,可是前提是咱們須要配置元數據以告知Spring容器,它纔可以經過讀取這些配置,來實例化,裝配和管理bean對象。spring
而配置元數據的方式,就是咱們今天要總結的三種,分別是XML,Java註解以及Java代碼。咱們經過這幾種方式,向Spring容器傳達這些對象之間豐富的相互依賴關係。sql
該圖是Spring如何工做的高級視圖。能夠看到,應用程序類與配置元數據相結合,在建立並初始化ApplicationContext以後,就能夠得到一個徹底配置和可執行的系統或應用程序。數據庫
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>
id屬性表示bean的惟一標識。安全
class屬性定義bean的類型並使用徹底限定的類名。架構
<!-- 1、使用默認構造函數建立,若是沒有該默認構造函數,則建立失敗。 --> <bean id="userService" class="com.smday.service.impl.UserServiceImpl"></bean> <!-- 2、使用普通公章中的方法建立對象(使用某個類中的方法建立對象,並存入spring容器 --> <bean id="instanceFactory" class="com.smday.factory.InstanceFactory"></bean> <bean id="userService" factory-bean="instanceFactory" factory-method="getUserService"></bean> <!-- 3、使用工廠中的靜態方法建立對象 --> <bean id="userService" class="com.smday.factory.StaticFactory" factory-method="getUserService"></bean>
在<bean>
標籤的內部定義<constructor-arg>
標籤。app
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean( AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; } }
<bean id="exampleBean" class="examples.ExampleBean"> <!-- constructor injection using the nested ref element --> <constructor-arg> <ref bean="anotherExampleBean"/> </constructor-arg> <!-- constructor injection using the neater ref attribute --> <constructor-arg ref="yetAnotherBean"/> <constructor-arg type="int" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
value:用於提供基本類型和String類型的數據。框架
ref:用於提供其餘的bean類型數據,在spring的ioc核心容器中出現過的bean對象。
在建立對象時,若是沒有提供構造器中的這些參數,將沒法建立該對象。
在<bean>
標籤的內部定義<property>
標籤。
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } }
<bean id="exampleBean" class="examples.ExampleBean"> <!-- setter injection using the nested ref element --> <property name="beanOne"> <ref bean="anotherExampleBean"/> </property> <!-- setter injection using the neater ref attribute --> <property name="beanTwo" ref="yetAnotherBean"/> <property name="integerProperty" value="1"/> </bean> <bean id="anotherExampleBean" class="examples.AnotherBean"/> <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
name:指定注入時調用的set方法的屬性名稱。
value:提供基本類型和String類型的數據。
ref:提供其餘的bean類型數據,在spring的ioc核心容器中出現過的bean對象。
若是某個成員必須有值,但並無提供相應的setter方法,將會出錯。
【集合類型的注入】:分爲list和map兩類結構
<bean id="userService" class="com.smday.service.impl.UserServiceImpl"> <property name="myStrs"> <array> <value>AAA</value> <value>BBB</value> <value>BBB</value> </array> </property> <property name="myList"> <list> <value>AAA</value> <value>BBB</value> <value>BBB</value> </list> </property> <property name="mySet"> <set> <value>AAA</value> <value>BBB</value> <value>BBB</value> </set> </property> <property name="myMap"> <map> <entry key="testA" value="AAA"></entry> <entry key="testB" > <value>BBB</value> </entry> </map> </property> <property name="myProp"> <props> <prop key="testC">CCC</prop> <prop key="testD">DDD</prop> </props> </property> </bean>
list結構可使用list、array和set標籤。
map結構可使用map和props標籤。
1、p-namespace使用bean元素的屬性來提供屬性值和協做bean,而不是使用嵌套的<property/>
元素,下面兩段bean的配置效果相同。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 傳統的xml聲明 --> <bean name="classic" class="com.example.ExampleBean"> <property name="email" value="foo@bar.com"/> </bean> <!-- p-namespace 聲明 --> <bean name="p-namespace" class="com.example.ExampleBean" p:email="foo@bar.com"/> </beans>
2、Spring 3.1中新引入的c-namespace容許使用內聯屬性來配置構造函數參數,而不是使用嵌套的<constructor-arg>
。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <!-- 傳統的xml聲明 --> <bean id="foo" class="x.y.Foo"> <constructor-arg ref="bar"/> <constructor-arg ref="baz"/> <constructor-arg value="foo@bar.com"/> </bean> <!-- c-namespace 聲明 --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/> </beans>
這兩個註解類是Spring's new java-configuration的核心構件。
@Bean註解用於指示方法實例化、配置和初始化要由Spring IoC容器管理的新對象,@Bean註解的做用與<bean/>
標籤相同。簡單的理解就是這個註解能夠告知spring,這個方法上面將來但願註冊一個應用上下文的bean對象,所以用@Bean註解的方法須要利用Java代碼,定義返回一個bean實例的邏輯。
@Configuration註解一個類代表這個類的主要目的是做爲bean定義的源,@Configuration類容許經過簡單地調用同一類中的其餘@Bean方法來定義bean之間的依賴關係。簡單的理解就是一個配置類,自此以後,你能夠在該配置類中完成在xml中完成的事,但形式會有所不一樣。
下面這個例子是一個最簡單的配置類的定義:
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
它的做用和下面這段xml配置的方式等價:
<beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans>
一個@Bean註釋的方法能夠有任意數量的參數來描述構建該bean所需的依賴關係。例如,若是咱們的TransferService須要一個AccountRepository,咱們能夠經過一個方法參數來實現這個依賴:
@Configuration public class AppConfig { @Bean public TransferService transferService(AccountRepository accountRepository) { return new TransferServiceImpl(accountRepository); } }
當spring調用transferService方法建立bean時,會自動裝配accountRepository到配置方法中,再次印證了那句話,帶有@Bean註解的方法能夠編寫任何須要的Java代碼來產生Bean的實例,例如構造器,setter方法,以及任何能夠產生實例的方法。
AnnotationConfigApplicationContext是Spring 3.0中新增的。它不只能夠接受@Configuration配置類做爲輸入,還能夠接受普通的@Component類和使用JSR-330元數據註釋的類。
初始化spring容器,獲取Myservice對象,調用對象的方法。
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
默認狀況下,配置類將會使用@Bean註解的方法的名稱做爲bean的名稱,這一點能夠經過name屬性修改。
@Configuration public class AppConfig { @Bean(name = "myFoo") public Foo foo() { return new Foo(); } }
如上:若是沒有指定name屬性,該bean的名稱爲foo,若是指定了name屬性,這裏的名稱就是myFoo。
Spring從如下兩個角度實現自動裝配:
首先仍是來看一段簡單的例子:
//定義一個UserService接口 public interface UserService { void add(); }
//定義實現類,注意加上@Component註解,告知spring建立這個bean @Component public class NormalUserServiceImpl implements UserService { @Override public void add() { System.out.println("添加用戶"); } }
//controller層,注意@Autowired註解,自動按類型注入Userservice @Component public class UserController { @Autowired private UserService userservice; public void add(){ userservice.add(); } }
//定義配置類,注意@ComponentScan("com.my.demo")註解開啓組件掃描 @Configuration @ComponentScan("com.my.demo") public class Appconfig { }
//整合junit測試類進行測試 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = Appconfig.class) public class UserServiceTest { @Autowired private UserService userservice; @Test public void testMethod(){ userservice.add(); } }
以上就是一套能夠正常運行的簡單案例,固然其中有很多可能出現的問題或者是其餘能夠實現相同功能的方案,咱們都暫且不提。其中出現了許多自動化裝配bean的註解,咱們一一來看:
【@Component】
值得一提的是,在三層架構中,Spring框架提供了明確的三層註釋,做用與@Component相同,但語義更加清晰明瞭,分別是:
Controller:表現層、Service:業務層、Respository:持久層
【@Autowired】
當出現歧義性時,知足類型要求的bean不是惟一時,能夠考慮使用@Qualifier和@Resource註解,參考:Spring解決自動裝配歧義性的幾種方案
【@Configuration】
【@ComponentScan】
設置spring組件掃描的基礎包的幾種方案:
@ComponentScan("com.my.demo")
@ComponentScan(basePackages = {"com.my.demo.web","com.my.demo.service"})
@ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class})
,相較於第二種,較爲安全。
須要注意的是,組件掃描默認是不開啓的,咱們須要經過該註解顯式通知Spring,告訴它去尋找帶有@Component註解的類,去建立該類的bean對象。
開啓組件掃描的xml方式:
<?xml version="1.0" encoding="UTF-8"?> <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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--配置掃描,至關於@ComponentScan("com.my.demo")--> <context:component-scan base-package="com.my.demo"/> </beans>
既然使用xml方式開啓組件掃描,那麼測試的時候須要謹慎,要讀取該xml文件:@ContextConfiguration("classpath:applicationContext.xml")
。
直接以例子呈現:
#jdbcConfig.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/spring jdbc.username=root jdbc.password=123456
/** * @author Summerday * <p> * 和spring鏈接數據庫相關的配置類 */ public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 建立queryRunner對象 * * @param dataSource * @return */ @Bean(name = "runner") @Scope("prototype") public QueryRunner createQueryRunner(DataSource dataSource) { return new QueryRunner(dataSource); } /** * 建立數據源對象 * * @return */ @Bean(name = "dataSource") public DataSource createDataSource() { try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass(driver); ds.setJdbcUrl(url); ds.setUser(username); ds.setPassword(password); return ds; } catch (Exception e) { throw new RuntimeException(e); } } }
【@Value】
/** * 主配置類 */ @Configuration @ComponentScan(basePackages = "com.smday") @Import(JdbcConfig.class) @PropertySource("classpath:JdbcConfig.properties") public class SpringConfiguration { }
【@Import】
【@PropertySource】
最後的最後,引用Spring in Action中做者的話:自動化配置、基於Java的顯式配置以及基於xml的顯式配置都描述了Spring應用中組件以及這些組件之間的關係。做者建議儘量使用自動化的配置,其次若是須要顯式配置,但願優先選擇基於Java的配置,類型安全且易懂。