原文連接http://zhhll.icu/2021/01/03/%E6%A1%86%E6%9E%B6/spring/spring%E9%85%8D%E7%BD%AEbean/java
構造器建立bean是最經常使用的,若是不使用構造注入,Spring會調用無參構造器來建立實例spring
使用的是反射機制,要求該bean所對應的類必須有一個無參構造器express
而對於注入方式,有構造器注入和setter方法注入ide
使用setter方法注入時,注意必定要有無參構造器,spring會根據配置的class來使用class.newInstance()方法來實例化該beanui
<?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 class 配置bean的全類名,使用反射的方式建立bean,要求必須有一個無參構造器 id 標識容器z中的bean id惟一 --> <bean id="helloWorld" class="com.zhanghe.study.spring4.beans.helloworld.HelloWorld"> <property name="name" value="Spring Hello"/> </bean> </beans>
注意:bean配置的property屬性的name值表示的是setter風格的屬性,即setter方法去掉set以後首字母小寫的名稱,並非和成員變量進行對應this
<!-- value爲屬性值 index 表示對應構造器的參數位置 從0開始 type 表示構造器該參數的類型 --> <bean id="car" class="com.zhanghe.study.spring4.beans.beantest.Car"> <constructor-arg value="法拉利" index="0"/> <constructor-arg value="20000.0" type="double"/> </bean>
獲取beanspa
// 建立spring的IOC容器 ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); // 從IOC容器獲取HelloWorld bean實例 HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
若是bean之間有引用關係,可使用ref來指定引用關係code
public class Person { private String name; private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", car=" + car + '}'; } }
這裏的ref中寫的是其餘bean的id值component
<bean id="car" class="com.zhanghe.study.spring4.beans.beantest.Car"> <constructor-arg value="法拉利" index="0"/> <constructor-arg value="20000.0" type="double"/> </bean> <bean id="person" class="com.zhanghe.study.spring4.beans.beantest.Person"> <property name="name" value="張三"/> <property name="car" ref="car"/> </bean>
可使用
、
xml
<bean id="person" class="com.zhanghe.study.spring4.beans.beantest.Person"> <property name="name" value="張三"/> <property name="car" ref="car"/> <property name="cars"> <!-- list的示例 --> <list> <ref bean="car"/> <ref bean="car2"/> </list> </property> <property name="carMap"> <!-- map的示例 entry可使用key/key-ref/value/value-ref --> <map> <entry key="AA" value-ref="car"/> <entry key="BB" value-ref="car2"/> </map> </property> </bean>
還有一種集合bean的方式,能夠進行配置集合屬性
<!-- 配置集合bean --> <util:list id="cars"> <ref bean="car"/> <ref bean="car2"/> </util:list>
而後在須要使用集合的bean中直接引用該集合bean
<bean id="person1" class="com.zhanghe.study.spring4.beans.beantest.Person"> <property name="name" value="張三"/> <property name="car" ref="car"/> <!-- 引用上述定義的集合bean --> <property name="cars" ref="cars"/> </bean>
能夠提供一個實現FactoryBean接口的工廠bean來生產所實際須要的bean對象
/** * 實現FactoryBean接口來生成car對象 * @author zh * @date 2021/1/30 16:01 */ public class CarFactoryBean implements FactoryBean<Car> { /** * 真正獲取對象的方法 * @return * @throws Exception */ @Override public Car getObject() throws Exception { return new Car("瑪莎拉蒂",300); } /** * 生成bean的類型 * @return */ @Override public Class<?> getObjectType() { return Car.class; } /** * 是不是單例 * @return */ @Override public boolean isSingleton() { return true; } }
使用該factoryBean對象時,因爲該bean實現了FactoryBean,因此spring不會把它做爲一個普通的bean來處理,而是做爲一個工廠bean,調用getObject()方法來建立實際須要的bean對象
<bean id="c" class="com.zhanghe.study.spring4.beans.beantest.CarFactoryBean"></bean>
使用靜態工廠方法建立bean實例時,class屬性也必須指定,此時的class屬性並非指定Bean實例的實現類,而是靜態工廠類,Spring經過該屬性知道由哪一個工廠類來建立Bean實例,還可使用factory-method屬性來指定靜態工廠方法,Spring將調用靜態工廠方法返回一個Bean實例,靜態工廠方法須要參數的話,使用
public class StaticCarFactory { private static Map<String,Car> cars = new HashMap<>(); static { cars.put("aa",new Car("aa",300)); } public static Car getCar(String name){ return cars.get(name); } }
<!-- 經過靜態工廠方法來配置bean class 靜態工廠類 factory-method 靜態工廠方法的名字 constructor-arg 指定靜態方法的參數 --> <bean id="car" class="com.zhanghe.study.spring4.beans.beantest.StaticCarFactory" factory-method="getCar"> <constructor-arg name="name" value="aa" index="0"/> </bean>
優勢:將對象建立的過程封裝到靜態方法中,當客戶端須要對象時,只須要簡單地調用靜態方法,不須要關係建立對象的細節
實例工廠與靜態工廠只有一個不一樣,靜態工廠只須要使用工廠類便可,實例工廠須要工廠實例,使用factory-bean指定工廠實例
public class InstanceCarFactory { private Map<String,Car> cars = null; public InstanceCarFactory(){ cars = new HashMap<>(); cars.put("bb",new Car("bb", 30000.0)); } public Car getCar(String name){ return cars.get(name); } }
<!-- 配置工廠實例 --> <bean id="instanceCarFactory" class="com.zhanghe.study.spring4.beans.beantest.InstanceCarFactory"/> <!-- 經過實例工廠方法來配置bean factory-bean 實例工廠的bean factory-method 實例工廠方法的名字 constructor-arg 指定方法的參數 --> <bean id="car1" factory-bean="instanceCarFactory" factory-method="getCar"> <constructor-arg name="name" value="bb" index="0"/> </bean>
上述的操做方式全是手動的進行注入的,如何進行自動裝配呢,可使用autowire屬性來配置
<!-- 自動裝配 --> <!-- byName 根據屬性名稱去匹配到對應的bean byName 根據屬性的類型去匹配到對應的bean --> <bean id="testAutoWired" class="com.zhanghe.study.spring4.beans.beantest.Person" autowire="byName"> <property name="name" value="張三"/> </bean>
若是使用byType,並且存在多個該類型的bean的話,就會出現異常
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.zhanghe.study.spring4.beans.beantest.Car' available: expected single matching bean but found 2: car,car2
spring能夠在classpath下進行組件掃描,包含註解有
spring掃描到組件後,有默認的命名策略,將掃描到的類名進行首字母小寫,也能夠在註解中使用value屬性值來標識組件的名稱
若是使用註解來標識bean的話,須要進行配置指定spring掃描的包,會掃描base-package指定的包及其子包
<context:component=scan base-package="包名"/>
<!-- 設置包掃描路徑 --> <context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest"> </context:component-scan>
還能夠自定義的設置對於該包下的某些組件是否進行掃描
在使用<context:component=scan base-package="包名"/>標籤時,記得要加上context的命名空間
使用context:exclude-filter來設置排除哪些特定的組件
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest"> <!-- 使用context:exclude-filter來設置排除哪些特定的組件 type annotation表示使用註解的表達式 assignable保護指定具體bean的類名 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
使用context:include-filter來設置只掃描哪些特定的組件
<context:component-scan base-package="com.zhanghe.study.spring4.beans.annotationtest" use-default-filters="false"> <!-- 使用context:include-filter來設置只掃描哪些特定的組件,若是使用include-filter的話須要設置use-default-filters="false" --> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>
使用xml進行自動裝配的時候略顯笨拙,並且使用起來也並不順心,由於autowire只能選擇byName或者byType,若是存在多個相同類型的bean使用byType就會出現問題,你們可能所以想要放棄自動裝配,其實自動裝配與註解搭配起來仍是很好用的,下面來了解一下
若是bean與bean之間如在關聯關係,如在beanA中須要調用beanB的方法,如何來獲取beanB中的實例呢
<context:component-scan>元素會自動註冊AutowiredAnnotationBeanPostProcessor實例,該實例能夠自動裝配具備@AutoWired、@Resource和@Inject註解的屬性
@Autowired默認使用byType,若是存在類型相同的兩個bean,則使用byName來根據屬性的名稱來匹配bean
@Resource註解是使用的byName,須要提供bean的名稱,若是不提供該bean的名稱,則自動使用屬性的名稱進行匹配
@Inject與@AutoWired同樣,只是沒有required屬性
使用@Autowired 和@Qualifier結合來明確指定須要裝配的Bean
@Autowired @Qualifier("bpmServiceImpl") private BpmService bpmService;
使用@Inject和@Named結合來指定
@Inject @Named("compensateServiceImpl") private CompensateService compensateService;
因爲自己的博客百度沒有收錄,博客地址http://zhhll.icu