Spring入门笔记(二)
SpringBean之间的关系
1、SpringBean之间的继承
假设现有一个Address类表示地点:
1package com.xpu.bean;
2
3public class Address {
4 private String city;
5 private String street;
6 setter()/getter()....
7}
现在如何需要两个对象,则可以这写:
1<bean id="address1" class="com.xpu.bean.Address" p:city="Xian" p:street="Wulukou"></bean>
2
3<bean id="address2" class="com.xpu.bean.Address" p:city="Xian" p:street="Beidajie"></bean>
但是这样写如果在类属性过多的时候就不是很好用了,所以,出现了配置之间的继承关系,但是这个和类之间的继承不是一回事:
1<bean id="address1" class="com.xpu.bean.Address" p:city="Xian" p:street="Wulukou"></bean>
2
3<!-- 配置之间的继承关系 :使用bean的parent属性指定-->
4<bean id="address2" p:street="Beidajie" parent="address1"></bean>
Spring 允许继承 bean 的配置, 被继承的 bean 称为父 bean. 继承这个父 Bean 的 Bean 称为子 Bean,子 Bean 从父 Bean 中继承配置, 包括 Bean 的属性配置,子 Bean 也可以覆盖从父 Bean 继承过来的配置,父 Bean 可以作为配置模板, 也可以作为 Bean 实例。 若只想把父 Bean 作为模板, 可以设置
1<-- 抽象bean不能被IOC容器实例化,只能用继承配置 -->
2<bean id="address1" class="com.xpu.bean.Address" abstract="true"></bean>
一旦这样配置之后这个配置是不能实例化出对象的,而需要配置出他的子配置,否则就无法创建对象,若某一个bean的class未指定,那么该bean必须是一个抽象bean,可以忽略父 Bean 的 class 属性,让子 Bean 指定自己的类,而共享相同的属性配置。但此时 abstract 必须设为 true,并不是
2、SpringBean之间的依赖
Spring 允许用户通过 depends-on 属性设定 Bean 前置依赖的Bean,前置依赖的 Bean 会在本 Bean 实例化之前创建好 如果前置依赖于多个 Bean,则可以通过逗号,空格或的方式配置 Bean 的名称
1public class Students {
2 private int stuId;
3 private String stuName;
4 private int stuAge;
5 private Address stuAdd;
6 setter()/getter()...
7}
这样需要在配置文件中的bean标签中使用depends-on属性来指定:
1<bean id="address" class="com.xpu.bean.Address" p:city="BeiJing" p:street="Hello"></bean>
2
3<bean id="student" class="com.xpu.bean.Students" p:stuId="1" p:stuName="Tim" p:stuAge="10" depends-on="address"></bean>
SpringBean的作用域
如何使用配置文件配置一个单例呢?
1<bean id="address" class="com.xpu.bean.Address">
2 <property name="city" value="BeiJing"></property>
3 <property name="street" value="WuLuKou"></property>
4</bean>
1ApplicationContext context = new ClassPathXmlApplicationContext("beans-relation.xml");
2Address bean1 = (Address) context.getBean("address");
3Address bean2 = (Address) context.getBean("address");
4System.out.println(bean1 == bean2);//true
由此可见,IOC容器对Bean的默认配置就是单例的:
在 Spring 中, 可以在 <bean>
元素的 scope
属性里设置 Bean 的作用域.
默认情况下, Spring 只为每个在 IOC 容器里声明的 Bean 创建唯一一个实例, 整个 IOC 容器范围内都能共享该实例:所有后续的 getBean() 调用和 Bean 引用都将返回这个唯一的 Bean 实例.该作用域被称为 singleton, 它是所有 Bean 的默认作用域,下面是scope 属性的说明:
类别 | 说明 |
---|---|
singleton | 在SpringIOC容器中仅存在一个Bean实例,Bean以单例的方式存在 |
prototype | 每次调用getBean()时都会返回一个新的实例 |
request | 每次HTTP请求都会创建一个新的Bean,该Bean作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同的Http Session使用不同的Bean,仅适用于WebApplicationContext环境 |
在单例模式下,一旦执行
1ApplicationContext context = new ClassPathXmlApplicationContext("beans-relation.xml");
就会构造出相应的对象,而无需等到context.getBean("address");
,每次获取对象的时候都会返回已经创建好的Bean,你可以理解为这是饿汉式单例,而prototype每次等到context.getBean("address");
才创建对象,你可以理解为这是一种很懒的方式,但是却不是单例模式
SpringBean使用外部属性文件
现在假设我们需要配置一个数据库连接,我们可以在配置文件中这样写:
1<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
2 <property name="user" value="root"></property>
3 <property name="password" value="1234"></property>
4 <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
5 <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_demo"></property>
6</bean>
接下来只需要这三个步骤便可以拿到数据库的连接对象:
1ApplicationContext context = new ClassPathXmlApplicationContext("beans-properties.xml");
2DataSource dataSources = (DataSource) context.getBean("dataSource");
3Connection connection = dataSources.getConnection();
可是这样的做法在配置项目特别多的时候就特别复杂,我们还是希望在配置文件层面上能解耦合,把数据库的连接信息独立到一个配置文件中,于是可以使用外部属性文件来完成:
在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离
Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量。 Spring 还允许在属性文件中使用 ${propName},以实现属性之间的相互引用。 这是我新建的db.properties配置文件:
1user=root
2password=1234
3driverClass=com.mysql.jdbc.Driver
4jdbcUrl=jdbc:mysql://127.0.0.1:3306/spring_demo
1<!-- 导入属性配置文件 -->
2<context:property-placeholder location="db.properties"/>
3
4<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
5 <property name="user" value="${user}"></property>
6 <property name="password" value="${password}"></property>
7 <property name="driverClass" value="${driverClass}"></property>
8 <property name="jdbcUrl" value="${jdbcUrl}"></property>
9</bean>
Spring表达式语言:SpEL
Spring 表达式语言(简称SpEL):是一个支持运行时查询和操作对象图的强大的表达式语言。
语法类似于 EL:SpEL 使用 #{…} 作为定界符,所有在大框号中的字符都将被认为是 SpEL
SpEL 为 bean 的属性进行动态赋值提供了便利
通过 SpEL 可以实现:
- 通过 bean 的 id 对 bean 进行引用
- 调用方法以及引用对象中的属性
- 计算表达式的值
- 正则表达式的匹配
1、字面量
2、引用 Bean、属性和方法
首先呢,还是拿Students和Address类作为演示:
1public class Address {
2 private String city;
3 private String street;
4 getter()/setter()...
5}
6
7public class Students {
8 private int stuId;
9 private String stuName;
10 private int stuAge;
11 private Address stuAdd;
12 getter()/setter()...
13}
- 引用其他对象,通过ID引用
1<bean id="address" class="com.xpu.bean.Address" p:city="Xian" p:street="Wulukou"></bean>
2
3<bean id="students" class="com.xpu.bean.Students">
4 <property name="stuId" value="1"></property>
5 <property name="stuName" value="Tom"></property>
6 <property name="stuAge" value="20"></property>
7 <property name="stuAdd" value="#{address}"></property>
8</bean>
- 引用其他对象的属性
1<bean id="address" class="com.xpu.bean.Address" p:city="Xian" p:street="Wulukou"></bean>
2
3<bean id="students" class="com.xpu.bean.Students">
4 <property name="stuId" value="1"></property>
5 <property name="stuName" value="#{address.city}"></property>
6 <property name="stuAge" value="20"></property>
7 <property name="stuAdd" value="#{address}"></property>
8</bean>
- 调用其他对象的方法,并支持链式调用
1<bean id="address" class="com.xpu.bean.Address" p:city="Xian" p:street="Wulukou"></bean>
2
3<bean id="students" class="com.xpu.bean.Students">
4 <property name="stuId" value="1"></property>
5 <property name="stuName" value="#{address.toString().trim()}"></property>
6 <property name="stuAge" value="20"></property>
7 <property name="stuAdd" value="#{address}"></property>
8</bean>
3、SpEL支持的运算符
-
算数运算符:
+
,-
,*
,/
,%
,^
-
加号还可以用作字符串连接
-
比较运算符:
<
、>
、==
、<=
、>=
、lt
、gt
、eq
、le
、ge
-
逻辑运算符号:
and
、or
、not
、|
-
if-else 运算符:
?: (ternary)
、?: (Elvis)
-
正则表达式:matches
-
调用静态方法或静态属性:通过 T() 调用一个类的静态方法,它将返回一个 Class Object,然后再调用相应的方法或属性,下面是一些使用示例:
1<bean>
2 <property name="add" value="#{students.id + 10}"></property>
3 <property name="sub" value="#{students.id - 10}"></property>
4 <property name="mul" value="#{students.id * 10}"></property>
5 <property name="div" value="#{students.id / 10}"></property>
6 <property name="rem" value="#{students.id % 10}"></property>
7 <property name="pow" value="#{students.id ^ 10}"></property>
8 <property name="stradd" value="#{students.name + '' +students.name}"></property>
9 <property name="equal" value="{students.id == 1}"></property>
10 <property name="logic_a" value="{students.id == 1 and students.age == 20}"></property>
11 <property name="logic_o" value="{students.id == 1 or students.age == 20}"></property>
12 <property name="logic_n" value="{not students.id == 1}"></property>
13 <property name="if-else" value="{students.id == 1 ? 'Tom':'Tim'}"></property>
14 <property name="PI" value="#{T(java.long.Math).PI}"></property>
15</bean>
IOC容器中Bean的生命周期方法
Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.。Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 1、通过构造器或工厂方法创建 Bean 实例
- 2、为 Bean 的属性设置值和对其他 Bean 的引用
- 3、调用 Bean 的初始化方法
- 4、Bean 可以使用了
- 5、当容器关闭时, 调用 Bean 的销毁方法
在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法。
1package com.xpu.bean_cycle;
2
3public class Car {
4 public Car() {
5 System.out.println("Car's Constructor...");
6 }
7
8 private String brand;
9
10 public void setBrand(String brand) {
11 System.out.println("setBrand...");
12 this.brand = brand;
13 }
14
15 public void init() {
16 System.out.println("init...");
17 }
18
19 public void destroy() {
20 System.out.println("distroy...");
21 }
22}
23
24//测试代码:
25public void test() {
26 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans-cycle.xml");
27 Car car = (Car) context.getBean("car");
28 System.out.println(car);
29 //关闭容器
30 context.close();
31}
bean的配置:
1<bean id="car" class="com.xpu.bean_cycle.Car" init-method="init" destroy-method="destroy">
2 <property name="brand" value="Audi"></property>
3</bean>
Bean 后置处理器
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例。 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性。
对Bean 后置处理器而言, 需要实现 BeanPostProcessor
接口。 在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:
1public Object postProcessAfterInitialization(Object beanObject, String id)
2public Object postProcessBeforeInitialization(Object beanObject, String id)
如何设置Bean的后置处理器呢?
使用一个类去实现BeanPostProcessor里面的上述两个方法,postProcessBeforeInitialization
是在init方法之前被调用,postProcessAfterInitialization
在init方法之后被调用,bean就是实例本身,beanName就是IOC容器中的bean配置的ID,返回值是实际上返回给用户的Bean,可以在以上两个方法中修改返回的Bean,甚至返回一个新的Bean,我们自己去实现BeanPostProcessor的类,只需要在IOC容器中配置一个Bean即可,无需指定ID和其他的东西,IOC容器会自动识别后置处理器:
添加Bean后置处理器后 Bean 的生命周期,Spring IOC 容器对 Bean 的生命周期进行管理的过程:
- 通过构造器或工厂方法创建 Bean 实例
- 为 Bean 的属性设置值和对其他 Bean 的引用
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessBeforeInitialization 方法
- 调用 Bean 的初始化方法
- 将 Bean 实例传递给 Bean 后置处理器的 postProcessAfterInitialization方法 Bean 可以使用了
- 当容器关闭时, 调用 Bean 的销毁方法
1public class MyBeanPostProcessor implements BeanPostProcessor{
2 @Override
3 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
4 System.out.println("postProcessBeforeInitialization"+bean+","+beanName);
5 if("Car".equals(beanName)) {
6 //...
7 }else if("XXX".equals(beanName)) {
8 //...
9 }
10 return bean;
11 }
12
13 @Override
14 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
15 System.out.println("postProcessAfterInitialization"+bean+","+beanName);
16 if("Car".equals(beanName)) {
17 //...
18 }else if("XXX".equals(beanName)) {
19 //...
20 }
21 return car;
22 }
23}
Bean 的配置方式
通过全类名(反射)、通过工厂方法(静态工厂方法 & 实例工厂方法)、FactoryBean,接下来我记录一下如何通过工厂方法来配置Bean:
1、静态工厂方法
调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节.
要声明通过静态方法创建的 Bean, 需要在 Bean 的 class 属性里指定拥有该工厂的方法的类, 同时在 factory-method
属性里指定工厂方法的名称. 最后, 使用 <constrctor-arg>
元素为该方法传递方法参数.
1package com.xpu.bean_factory;
2
3import java.util.HashMap;
4import java.util.Map;
5
6/**
7 * 静态工厂方法:直接调用某一个类的静态方法就可以返回一个bean的实例
8 */
9public class StaticCarFactory {
10 private static Map<String, Car> cars = new HashMap<>();
11
12 static {
13 cars.put("audi", new Car("audi",300000));
14 cars.put("ford", new Car("ford",400000));
15 }
16
17 //静态工厂方法
18 public static Car getCar(String name) {
19 return cars.get(name);
20 }
21}
1<!-- 通过静态方法工厂来配置Bean,注意不是配置静态方法工厂实例,而是Bean实例 -->
2<!-- class属性指向静态方法工厂的Class
3 factory-method属性指向静态工厂的名字
4 constructor-arg如果工厂方法需要传入参数,则使用constructor-arg来配置参数
5 -->
6<bean id="car1" class="com.xpu.bean_factory.StaticCarFactory" factory-method="getCar">
7 <constructor-arg value="audi"></constructor-arg>
8</bean>
2、实例工厂方法
实例工厂方法: 将对象的创建过程封装到另外一个对象实例的方法里. 当客户端需要请求对象时, 只需要简单的调用该实例方法而不需要关心对象的创建细节. 要声明通过实例工厂方法创建的 Bean
- 在 bean 的 factory-bean 属性里指定拥有该工厂方法的 Bean
- 在 factory-method 属性里指定该工厂方法的名称
- 使用 construtor-arg 元素为工厂方法传递方法参数
1package com.xpu.bean_factory;
2
3import java.util.HashMap;
4import java.util.Map;
5
6/**
7 * 实例工厂的方法,即先需要创建工厂本身,再调用工厂的实例方法,再返回Bean实例
8 */
9public class InstanceCarFactory {
10 private static Map<String, Car> cars = null;
11 public InstanceCarFactory() {
12 cars = new HashMap<>();
13 cars.put("audi", new Car("audi",300000));
14 cars.put("ford", new Car("ford",400000));
15 }
16
17 public Car getCar(String brand) {
18 return cars.get(brand);
19 }
20}
1<!-- 配置工厂的实例 -->
2<bean id="carFactory" class="com.xpu.bean_factory.InstanceCarFactory"></bean>
3
4<!-- 通过实例工厂方法来配置Bean -->
5<!-- factory-bean属性指向实例方法工厂的Class
6 factory-method属性指向实例工厂的名字
7 constructor-arg如果工厂方法需要传入参数,则使用constructor-arg来配置参数
8 -->
9<bean id="car2" factory-bean="carFactory" factory-method="getCar">
10 <constructor-arg value="ford"></constructor-arg>
11</bean>
3、FactoryBean
实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean,Spring 中有两种类型的 Bean, 一种是普通Bean, 另一种是工厂Bean,即FactoryBean.。
工厂 Bean 跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂 Bean 的 getObject 方法所返回的对象 ,示例如下:
1package com.xpu.factory_spring;
2
3import org.springframework.beans.factory.FactoryBean;
4
5//自定义的FactoryBean需要实现Spring提供的FactoryBean接口
6public class CarFactoryBean implements FactoryBean<Car> {
7
8 private String brand;
9 public void setBrand(String brand) {
10 this.brand = brand;
11 }
12
13 //返回Bean的对象
14 @Override
15 public Car getObject() throws Exception {
16 return new Car(brand, 500000);
17 }
18
19 //返回Bean的类型
20 @Override
21 public Class<?> getObjectType() {
22 return Car.class;
23 }
24
25 //是否是单例的
26 @Override
27 public boolean isSingleton() {
28 return true;
29 }
30}
1<!-- 通过FactoryBean来配置Bean的实例
2 class执行FactoryBean的全类名
3 property配置的是FactoryBean的属性,但是返回的FactoryBean的getObject()方法返回的实例
4 -->
5<bean id="car" class="com.xpu.factory_spring.CarFactoryBean">
6 <property name="brand" value="BMW"></property>
7</bean>
4、基于注解的方式
接下来说说基于注解的方式配置Bean,这也是常见的方式: 组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件,特定组件包括:
@Component
: 基本注解,标识了一个受 Spring 管理的组件@Respository
: 标识持久层组件@Service
: 标识服务层(业务层)组件@Controller
: 标识表现层组件
对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写, 也可以在注解中通过 value 属性值标识组件的名称
当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明需要扫描的包,而且不要忘记声明命名空间<context:component-scan>
:
1<context:component-scan base-package="com.xpu.annnotations"></context:component-scan>
base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类。当需要扫描多个包时, 可以使用逗号分隔,如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern
属性过滤特定的类,示例:
1<!-- 可以通过resource-pattern可以指定扫描的资源 -->
2<context:component-scan base-package="com.xpu.annnotations" resource-pattern="service/*.class" ></context:component-scan>
<context:include-filter>
子节点表示要包含的目标类<context:exclude-filter>
子节点表示要排除在外的目标类<context:component-scan>
下可以拥有若干个<context:include-filter>
和<context:exclude-filter>
子节点
1<!-- context:exclude-filter就是排除哪些类 -->
2<context:component-scan base-package="com.xpu.annnotations" use-default-filters="false">
3 <context:exclude-filter type="annotation" expression="com.xpu.annnotations.controller.UserController"/>
4</context:component-scan>
5
6<context:component-scan base-package="com.xpu.annnotations" use-default-filters="false">
7 <context:include-filter type="annotation" expression="com.xpu.annnotations.controller.UserController"/>
8</context:component-scan>
注意对于那些已经配置了注解的类,想要使自己的过滤器生效,就需要配置一个use-default-filters="false"
要求不要使用默认的过滤器!
<context:include-filter>
和 <context:exclude-filter>
子节点支持多种类型的过滤表达式:
类别 | 示例 | 说明 |
---|---|---|
annotation | com.xpu.XxxAnnotation | 所有标注了XxxAnnotation的类,该类型采用目标类型是否标注了某个注解进行过滤 |
assinable | com.xpu.XxxService | 继承或者扩展 XxxService的类,该类型采用目标类型是否继承或者拓展某个特定的类进行过滤 |
aspectj | com.xpu.*Service+ | 所有类名以Service结束及继承或扩展它们的类,该类型采用aspectJ表达式进行过滤 |
regex | com.xpu.anno.* | 所有com.xpu.anno包下的类,该类型采用正则表达式根据类名进行过滤 |
custom | com.xpu.XxxTypeFilter | 采用XxxTypeFilter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口 |
组件装配
<context:component-scan>
元素还会自动注册AutowiredAnnotationBeanPostProcessor 实例, 该实例可以自动装配具有 @Autowired 和 @Resource 、@Inject注解的属性:
1、使用 @Autowired 自动装配Bean
@Autowired
注解自动装配具有兼容类型的单个 Bean属性
-
构造器, 普通字段(即使是非 public),一切具有参数的方法都可以应用
@Authwired
注解 -
默认情况下, 所有使用 @Authwired 注解的属性都需要被设置,当 Spring 找不到匹配的 Bean 装配属性时,会抛出异常,若某一属性允许不被设置,可以设置 @Authwired 注解的 required 属性为 false
-
默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作。 此时可以在 @Qualifier 注解里提供 Bean 的名称。 Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称
-
@Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配。
-
@Authwired 注解也可以应用在集合属性上,此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.
-
@Authwired 注解用在 java.util.Map 上时,若该 Map 的键值为 String,那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值
1@Controller("userController")
2public class UserController {
3 @Autowired(required=false)
4 private UserService userService;
5
6 @Autowired
7 public void setUserService(UserService userService) {
8 this.userService = userService;
9 }
10
11 public void execute() {
12 System.out.println("UserController execute()...");
13 userService.add();
14 }
15}
现在假设IOC容器中没有userService这个Bean,那么Spring会抛出异常,不过给配置一个@Autowired(required=false)
即可,如果像这样的UserResponseImpl这样的类没有指定Repository中的名称,于是便可以使用@Qualifier("userResponseImpl")
注解类中依赖的属性名称,这就好像如果你不自己给自己取个名字,那么就只能用系统给你的默认的名称,下面是示例:
1@Service
2public class UserService {
3 @Autowired
4 @Qualifier("userResponseImpl")
5 private UserResponse userResponse;
6 public void add() {
7 System.out.println("UserService add()...");
8 userResponse.save();
9 }
10 public UserResponse getUserResponse() {
11 return userResponse;
12 }
13 public void setUserResponse(@Qualifier("userResponseImpl") UserResponse userResponse) {
14 this.userResponse = userResponse;
15 }
16}
Spring 还支持 @Resource 和 @Inject 注解,这两个注解和 @Autowired 注解的功用类似: 1、@Resource 注解要求提供一个 Bean 名称的属性,若该属性为空,则自动采用标注处的变量或方法名作为 Bean 的名称 2、@Inject 和 @Autowired 注解一样也是按类型匹配注入的 Bean, 但没有 reqired 属性,建议使用 @Autowired 注解
Spring泛型依赖注入
Spring 4.x 中可以为子类注入子类对应的泛型类型的成员变量的引用: 现在假设有如下类,从UML中也可以看出这几个类的关系:
1<context:component-scan base-package="com.xpu.generic"></context:component-scan>
1public class BaseService<T> {
2 @Autowired
3 protected BasetRepository<T> repository;
4
5 public void add() {
6 System.out.println("add");
7 System.out.println(repository);
8 }
9}
10
11@Service
12public class UserService extends BaseService<User>{ }
13
14public class Demo{
15 public void test(){
16 ApplicationContext context = new ClassPathXmlApplicationContext("beans-generic-di.cml.xml");
17UserService service = (UserService) context.getBean("userService");
18 service.add();
19 }
20}
泛型依赖注入就是允许我们在使用spring进行依赖注入的同时,利用泛型的优点对代码进行精简,将可重复使用的代码全部放到一个类之中,方便以后的维护和修改。同时在不增加代码的情况下增加代码的复用性。Spring 4.0开始支持的泛型依赖注入对于我们使用泛型非常重要,以后还会经常遇到的!