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阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容