Spring學習筆記 | 詳解bean的配置(三):繼承配置 | 外部文件配置 | 工廠方法配置 | 注解配置 | 泛型依賴注入

繼承Bean配置

  • Spring允許繼承bean的配置,被繼承的bean稱為父bean,繼承這個父bean的bean稱為子bean。通過設置parent來實現繼承。
  • 子bean從父bean中繼承配置,包括bean的屬性配置
  • 子bean可以覆蓋從父bean繼承過來的配置。
  • 父bean可以作為配置模板,也可以作為bean實例,若只想把父bean作為模板,可以設置<bean>abstract屬性為true這樣Spring將不會實例化這個bean。
  • 并不是<bean>元素里的所有屬性都會被繼承,比如:autowire,abstract等。
  • 可以忽略父bean的class屬性,讓子bean指定自己的類,而共享相同的屬性配置,但是此時abstract必須設為true

我們此時有兩個 address類型的bean,如下:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.spring.autowire.Address" p:city="BeiJing" p:street="WuDaoKou"></bean>
    <bean id="address1" class="com.spring.autowire.Address" p:city="BeiJing" p:street="DaZhongSi"></bean>

</beans>

兩個bean之間有很多相同的屬性比如classcity,因此我們如果讓第二個bean繼承第一個bean,再把不同的屬性加以覆蓋,就可以使該配置文件簡易許多:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.spring.autowire.Address" p:city="BeiJing" p:street="WuDaoKou"></bean>
    <bean id="address1" p:street="DaZhongSi" parent="address"></bean>

</beans>

如果想把第一個bean不被實例化,只作為其他bean的模板bean,則可以將其設置為抽象bean:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address"  class="com.spring.autowire.Address" p:city="BeiJing" p:street="WuDaoKou" abstract="true"></bean>
    <bean id="address1"  p:street="DaZhongSi" parent="address"></bean>

</beans>

此時要切記抽象bean不能被實例化。


依賴bean配置

  • Spring允許用戶通過depend-on屬性設定bean前置依賴的bean,前置依賴的bean會在本bean實例化之前創建好。
  • 如果前置依賴于多個bean,則可以通過逗號,空格等方式配置bean的名稱。

bean的作用域

使用<bean>scope屬性來配置bean的作用域:

  • singleton:默認值。在IOC容器初始化時創建bean實例,在整個容器的生命周期內只創建這一個bean,是單例的
  • prototype:原型的。IOC容器初始化時不創建bean的實例,而在每次請求時都創建一個新的bean實例,并返回。

例如:

<?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="car" class="com.spring.autowire.Car" scope="prototype">
        <property name="brand" value="Audi"/>
        <property name="price" value="300000"/>
    </bean>
</beans>

使用外部屬性文件

在配置文件里配置bean時,有時需要在bean的配置里混入系統部署的細節信息(例如:文件路徑,數據源配置信息等),而這些部署細節實際上需要和bean配置相分離。

Spring提供了一個PropertyPlaceholderConfigurerBeanFactory后置處理器,這個處理器允許用戶將bean配置的部分內容外移到屬性文件中,可以在bean配置文件里使用形式為${var}的變量,PropertyPlaceholderConfigurer從屬性文件里加載屬性,并使用這些屬性來替換變量。

Spring還允許在屬性文件中使用${propName}以實現屬性之間的相互引用。

示例:
如果我們不使用外部屬性文件的話,在beans-properties.xml配置DataSource類型的一個bean如下:

<?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/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"/>
        <property name="password" value="root"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///my_test_mysql"/>
    </bean>

</beans>

這樣也能配置,但是就顯得不大靈活了,當我們需要更改這些數據庫屬性參數時還得進該配置文件來更改。

如果我們使用外部資源文件來進行配置,步驟如下:
我們定義一個外部的資源文件db.properties,里面存放數據庫的屬性配置:

user=root
password=root
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///my_test_mysql

bean配置文件beans-properties.xml,里面配置了DataSource類型的bean:

<?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/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    <!--導入屬性文件-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--配置bean-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
        <property name="driverClass" value="${driverClass}"/>
        <property name="jdbcUrl" value="${jdbcUrl}"/>
    </bean>
</beans>

通過工廠方法配置bean

靜態工廠方法

調用靜態工廠方法創建bean是將對象創建的過程封裝到靜態方法中,當客戶端需要對象時,只需要簡單地調用靜態方法,而不用關心創建對象的細節。

要聲明通過靜態方法創建的bean,需要在bean的class屬性里指定擁有該工廠的方法的類,同時在配置文件中進行配置,具體屬性如下:

  • class屬性:指向靜態工廠方法的全類名
  • factory-method:指向靜態工廠方法的名字
  • construtor-arg:如果工廠方法需要傳入參數,則使用construtor-arg來配置參數

示例:

  • 創建bean類:
package com.spring.factory;

public class Car {
    private String brand;
    private double price;

    public Car(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public Car() {
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "brand='" + brand + '\'' +
                ", price=" + price +
                '}';
    }
}

  • 創建靜態工廠類:
package com.spring.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 靜態工廠方法:直接調用某一個類的靜態方法就可以返回bean實例
 */
public class StaticCarFactory {
    private static Map<String,Car> cars = new HashMap <String, Car>();

    static {
        cars.put("audi",new Car("audi",100000));
        cars.put("ford",new Car("ford",200000));
    }

    //靜態工廠方法
    public static Car getCar(String carName) {
        return cars.get(carName);
    }
}

beans-factory.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 通過靜態工廠方法配置bean,注意不是配置靜態工廠方法實例,而是配置bean實例-->
    <bean id="car1" class="com.spring.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="audi"></constructor-arg>
    </bean>
</beans>

實例工廠方法

將對象的創建過程封裝到另外一個對象實例的方法里,當客戶端需要請求對象時,只需要簡單的調用該實例方法而不需要關心對象的創建細節。

要聲明通過實例工廠方法創建的bean,需要如下步驟:

  • factory-bean:指定擁有該工廠方法的bean
  • factory-method:指向靜態工廠方法的名字
  • constructor-arg:如果工廠方法需要傳入參數,則使用construtor-arg來配置參數

實例:
bean類我們使用靜態工廠方法時創建的bean類,因此我們不需要創建新的bean類。

  • 創建實例工廠方法類:
package com.spring.factory;

import java.util.HashMap;
import java.util.Map;

/**
 * 實例工廠方法:實例工廠的方法,即先要創建工廠本身,再調用工廠的實例工廠來返回bean的實例
 *
 */
public class InstanceCarFactory {
    private Map<String,Car> cars = null;

    public InstanceCarFactory(){
        cars = new HashMap <String, Car>();
        cars.put("audi",new Car("audi",1000000));
        cars.put("ford",new Car("ford",2000000));

    }

    public Car getCar(String brand){
        return cars.get(brand);
    }
}

  • beans-factory.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 通過靜態工廠方法配置bean,注意不是配置靜態工廠方法實例,而是配置bean實例-->
    <bean id="car1" class="com.spring.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="audi"></constructor-arg>
    </bean>

    <!-- 配置工廠的實例-->
    <bean id="carFactory" class="com.spring.factory.InstanceCarFactory"></bean>

    <!-- 通過實例工廠來配置bean-->
    <bean id="car2" factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="ford"></constructor-arg>
    </bean>
</beans>

通過FactoryBean配置bean

通過factoryBean來配置bean的實例
class:指向FactoryBean的全類名
property:配置FactoryBean的屬性
但實際返回的實例卻是FactoryBean的getObject()返回的實例。

package com.spring.factoryBean;

import org.springframework.beans.factory.FactoryBean;

public class CarFactoryBean implements FactoryBean<Car> {

    private String brand;

    public void setBrand(String brand) {
        this.brand = brand;
    }

    //返回bean的對象
    @Override
    public Car getObject() throws Exception {
        return new Car(brand,10000);
    }

    //返回bean的類型
    @Override
    public Class < ? > getObjectType() {
        return Car.class;
    }

    //返回是否是單實例
    @Override
    public boolean isSingleton() {
        return false;
    }
}

<?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">

    <!--
        通過factoryBean來配置bean的實例
        class:指向FactoryBean的全類名
        property:配置FactoryBean的屬性
        但實際返回的實例卻是FactoryBean的getObject()返回的實例。
    -->
    <bean id="car" class="com.spring.factoryBean.CarFactoryBean">
        <property name="brand" value="BMW"></property>
    </bean>
</beans>

通過注解配置bean(一):基于注解配置bean

我們首先要先引入一個掃描組件的概念。

在classpath中掃描組件

Spring能夠從classpath下自動掃描,偵測和實例化具有特定注解的組件,我們稱為組件掃描。

特定組件包括:

  • @Component:基本注解,標識了一個受Spring管理的組件
  • @Respository:標識持久層組件
  • @Service:標識服務層(業務層)組件
  • @Controller:標識表現層組件

對于掃描到的組件,Spring有默認的命名策略:使用非限定類名,第一個字母小寫,也可以在注解中通過value屬性值標識組件的名稱

當在組件類上使用了特定的注解之后,還需要在Spring的配置文件中聲明<context:component-scan>

  • base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描這個基類包里及其子包中的所有類。
  • 當需要掃描多個包時,可以使用逗號分隔
  • 如果僅僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類,示例:
<context:component-scan 
    base-package="com.spring.annotation" 
    resource-pattern="repository/*.class"></context:component-scan>
  • <context:include-filter>子節點表示要包含的目標類,需要與context:component-scan節點中use-default-filters配合使用(設置為false
  • <context:exclude-filter>子節點表示要排除在外的目標類
  • <context:component-scan>下可以擁有若干個<context:include-filter><context:exclude-filter>字節。
  • <context:include-filter><context:exclude-filter>子節點支持多種類型的過濾表達式,在此介紹兩種:
類別 示例 說明
annotation com.cerr.XxxAcnotaion 所有標注了XXXAnnotation的類。該類型采用目標類是否標注了某個注解進行過濾
assinable com.cerr.XxxService 所有繼承或擴展XXXService的類。該類型采用目標類是否繼承或擴展某個特定類進行過濾。

配置示例:

<?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">


    <!-- 指定SpringIOC容器掃描的包 -->
    <!-- 可以通過resource-pattern指定掃描的資源 -->
    <!--
    <context:component-scan base-package="com.spring.annotation" resource-pattern="repository/*.class"></context:component-scan>
    -->
    


    <context:component-scan base-package="com.spring.annotation" use-default-filters="false">
        <!-- context:exclude-filter子節點指定排除哪些指定表達式的組件-->
        <!--
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        -->

        <!-- context:include-filter子節點指定包含哪些指定表達式的組件,需要與context:component-scan節點中use-default-filters配合使用-->
        <!--
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        -->
        <!--
        <context:exclude-filter type="assignable" expression="com.spring.annotation.repository.UserRepository"/>
        -->
        <!--
        <context:include-filter type="assignable" expression="com.spring.annotation.repository.UserRepository"/>
        -->
    </context:component-scan>
</beans>

通過注解配置bean(二)

如果多個bean之間有關聯,比如我們定義一個接口UserRepository如下:

package com.spring.annotation.repository;

public interface UserRepository {
    void save();
}

其有一個實現類UserRepositoryImpl

package com.spring.annotation.repository;

import org.springframework.stereotype.Repository;

@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository{

    @Override
    public void save() {
        System.out.println("UserRepository Save..");
    }
}

有一個UserService類有該接口類型的成員變量:

package com.spring.annotation.service;

import com.spring.annotation.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    private UserRepository userRepository;
    public void add(){
        System.out.println("UserService add..");
        userRepository.save();
    }
}

然后還有一個UserController類也有一個UserService類型的變量。

package com.spring.annotation.controller;

import com.spring.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {

    private UserService userService;

    public void execute(){

        System.out.println("UserController execute...");
        userService.add();
    }
}

這三個類之間就存在了關聯關系,然后我們在beans-annotation.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">


    <context:component-scan base-package="com.spring.annotation"></context:component-scan>
</beans>

我們在主方法中獲取UserController的bean對象并且調用其execute():

package com.spring.annotation;

import com.spring.annotation.controller.UserController;
import com.spring.annotation.repository.UserRepository;
import com.spring.annotation.repository.UserRepositoryImpl;
import com.spring.annotation.service.UserService;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");
        System.out.println(userController);
        userController.execute();
    }
}

運行代碼會發現出現異常,因為UserController的bean對象的方法中有使用到UserService的bean對象,而在UserService對象的方法中也使用到了UserRepository接口,而此時他們都未裝配,因此就出現了異常。

對于上述的異常,我們可以使用@Autowired進行自動裝配,即在要使用到的成員類進行注解或者注解其setter方法也可。

<context:component-scan>元素還會自動注冊AutowiredAnnotationBeanPostProcessor實例,該實例可以自動裝配具有@Autowired@Resource@Inject注解的屬性。

使用@Autowired自動裝配bean

@Autowired注解可以自動裝配具有兼容類型的單個bean屬性:

  • 構造器,普通字段(即使是非public),一切具有參數的方法都可以應用@Autowired注解
  • 默認情況下,所有使用@Autowired注解的屬性都需要被設置,當Spring找不到匹配的bean裝配屬性時,會拋出異常,即我們要在配置文件中配置它,**若某一屬性允許不被設置,可以設置@Autowired注解的request屬性為false,例如@Autowired(request=false)
    對于上面錯誤的例子,我們對其加了注解后的代碼如下:
package com.spring.annotation.controller;

import com.spring.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    //加了注解
    @Autowired
    private UserService userService;

    public void execute(){

        System.out.println("UserController execute...");
        userService.add();
    }
}
package com.spring.annotation.service;

import com.spring.annotation.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    //加了注解
    @Autowired
    private UserRepository userRepository;
    public void add(){
        System.out.println("UserService add..");
        userRepository.save();
    }
}
  • 默認情況下,當IOC容器里存在多個類型兼容的bean時,通過類型的自動裝配將無法工作,此時可以在@Qualifier注解里提供bean的名稱,Spring允許對方法的入參標注@Qualifiter已指定注入的bean的名稱。
    例如我們此時多定義一個UserRepository的實現類UserJdbcRepository
package com.spring.annotation.repository;
import org.springframework.stereotype.Repository;
@Repository
public class UserJdbcRepository implements UserRepository{
    @Override
    public void save() {

    }
}

我們再把UserRepositoryImpl中的@Repository("userRepository")的命名去掉,變為@Repository。此時我們有了兩個UserRepository接口的實現類,而此時通過@AutoWired注解的是UserRepository接口,因此允許代碼會出現異常。

我們此時有兩種解決方法,可以在UserRepositoryImpl中的@Repository中加上我們注解的userRepository。另一種方法使用@Qualifiter注解提供bean的名稱。

注解后的UserService如下所示:

package com.spring.annotation.service;

import com.spring.annotation.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    @Autowired
    @Qualifier("userRepositoryImpl")
    private UserRepository userRepository;
    public void add(){
        System.out.println("UserService add..");
        userRepository.save();
    }
}
  • @Autowired注解也可以應用在數組類型的屬性上,此時Spring將會把所有匹配的bean進行自動裝配。
  • @Autowired注解也可以應用在集合屬性上,此時Spring讀取該集合的類型信息,然后自動裝配所有與之兼容的bean。
  • @Autowired注解用在java.util.Map上時,若該Map的鍵值是String,那么Spring將自動裝配與之Map值類型兼容的bean,此時bean的名稱作為鍵值。

使用@Resource或@Inject自動裝配bean

這兩者與@Autowired注解的功能類似。

@Resource注解要求提供一個bean名稱的屬性,若該屬性為空,則自動采用標注處的變量或方法名作為bean的名稱

@Inject@Autowired注解一樣也是按類型匹配注入的bean,但沒有required屬性。我們建議使用@Autowired注解。


泛型依賴注入(Spring4的新特性)

Spring 4中可以為子類注入子類對應的泛型類型的成員變量的引用。

即父類泛型類型之間建立了關聯關系,而對應的子類之間沒有建立關聯關系,Spring會為其對應的子類建立關聯關系。

我們以下圖所示的uml圖來舉例:


類圖

我們現在有兩個泛型父類BaseService<T>BaseRepository< T >BaseRepository<T>BaseService<T>的成員變量,代碼如下:

package com.spring.generic.di;

import org.springframework.beans.factory.annotation.Autowired;

public class BaseService<T> {

    @Autowired
    protected  BaseRepository<T> repository;

    public void add(){
        System.out.println("add");
        System.out.println(repository);
    }
}
package com.spring.generic.di;

public class BaseRepository< T > {
}

有一個User類如下:

package com.spring.generic.di;

public class User {
}

上述兩個泛型基類的兩個子類UserServiceUserRepository代碼如下(這兩個子類之間沒有建立關聯關系):

package com.spring.generic.di;

import org.springframework.stereotype.Service;

@Service
public class UserService extends BaseService<User> {
}
package com.spring.generic.di;

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository extends BaseRepository<User> {
}

在配置文件beans-generic-di.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">
    <context:component-scan base-package="com.spring.generic.di"/>
</beans>

主方法:

package com.spring.generic.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-generic-di.xml");

        UserService userService = (UserService) ctx.getBean("userService");
        userService.add();
    }
}

運行后控制臺打印如下:

add
com.spring.generic.di.UserRepository@6d3af739

我們發現其子類之間也自動的建立了關聯關系,自動初始化了UserRepository類。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容