Spring中的依赖注入的三种方法
基于构造方法
setter注入(常用)
接口注入(不常用)
Bean如下
package spring;
public class Role {
private Long id;
private String roleName;
private String note;
setter/getter...
}
构造注入配置
<bean id="role" class="spring.Role">
<constructor-arg index="0" value="小红"></constructor-arg>
<constructor-arg index="1" value="小红的描述"></constructor-arg>
</bean>
其中index代表第几个参数,从0开始,value是为参数复制的值
setter注入:
<bean id="role" class="spring.Role">
<constructor-arg index="0" value="小红"></constructor-arg>
<constructor-arg index="1" value="小红的描述"></constructor-arg>
<property name="roleName" value="熊明"></property>
<property name="note" value="熊明的描述"></property>
</bean>
这里也可以将构造配置去掉,这里没有去掉是为了验证,setter注入的值会将构造参数的值给覆盖
接口注入(因为配置较麻烦,故这里不讲解,不过可以提示通过JNDI的形式去获取)
Bean装配的3种方式
1、在XML中显示配置
2、在java的接口和类中实现配置(注解)
3、隐式Bean的发现机制和自动装配原则
其使用优先顺序为:3>2>1
常用规则:注解为主,xml为辅助
待装配的Bean:
public class ComplexAssembly {
private Long id;
private List<String> list;
private Map<String,String> map;
private Set<String> set;
private String[] array;
private Properties properties;
setter/getter...
}
Xml装配Bean
<bean id="complexAssembly" class="spring.ComplexAssembly">
<property name="id" value="1"></property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="map">
<map>
<entry key="map1" value="map-value1"></entry>
<entry key="map2" value="map-value2"></entry>
<entry key="map3" value="map-value3"></entry>
</map>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="array">
<list>
<value>array1</value>
<value>array2</value>
</list>
</property>
<property name="properties">
<props>
<prop key="prop1">value-prop-1</prop>
<prop key="prop1">value-prop-2</prop>
</props>
</property>
</bean>
通过注解装配Bean
@Component
public class Role1 {
@Value("1")
private Long id;
@Value("小明")
private String roleName;
@Value("小明的描述")
private String note;
setter/getter...
}
注意:这里如果添加了带参构造方法,并且没有对应的Bean对象注入就会报错
No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
扫描类:
@ComponentScan(basePackages = "spring")
public class PojoConfig {
}
这里可以通过{“package1","package2"}来实现多个包的制定扫描
调用代码:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(PojoConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String string:
beanDefinitionNames) {
System.out.println(string);
}
Role1 bean = context.getBean(Role1.class);
System.out.println(bean.getRoleName());
};
}
ComponmentScan注解面临两个问题:
需要实现扫名制定的类(采用basePackages解决)
没有注入对象(采用@Autowired解决)
自动装配@Autowired
@Component(value = "roleService")
public class RoleService implements Service {
@Autowired
private Role1 role1 = null;
@Override
public void printInfo() {
System.out.println(role1.getRoleName()+role1.getNote());
}
setter/getter...
}
调用代码:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(PojoConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String string:
beanDefinitionNames) {
System.out.println(string);
}
Role1 bean = context.getBean(RoleService.class);
bean.printInfo();
};
}
@Primary和@Qualifier消除自动装配的歧义性
public class Main {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(PojoConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String string:
beanDefinitionNames) {
System.out.println(string);
}
Service bean = context.getBean(Service.class);
bean.printInfo();
};
}
该图中,Service是一个接口,如果该接口中有两个以上的实现类,都进行了IOC管理,那么这时候spring在使用自动装配的时候就会犯迷糊,所以我们要处理这种情况
@Primary可以实现优先注入,如果给一个类使用了该注解,那么当出现多个同类型Bean的时候,该类Bean优先被注入
@Qualifier可以指定按照名称来注入,不会出现上述问题
public class RoleController {
@Autowired
@Qualifier("roleService")
private Service service;
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
}
上图代码,就可以确定,即使出现同一接口下的不同子类中,会将id=roleService的实例进行注入
使用@Bean装配Bean
@Component不能够注解到方法上,所以就需要使用@Bean,该注解是将方法中的返回Bean交给IoC容器管理
@Bean(name = "dataSource")
public DataSource getDataSource(){
DataSource dataSource;
...
return dataSource;
}
这时候IOC容器在扫描它的时候就会得到一个dataSource对象,进而对其进行管理,通过@Bean注解也是可以实现自定义初始化方法和销毁方法的
装配混合使用
可以通过@ImportResource("classpath:spring-dataSource.xml")来在配置类中引入其他的xml配置文件,也可以通过在一个xml文件中通过<import resourse="spring-datasource.xml>导入另外一个xml配置文件,对于多个配置类,可以在一个配置类中通过@Import({ApplicationConfig2.class,ApplicationConfig3.class})来导入,而而配置类就是在类上加上注解@ComponentScan注解的类,该类不用实现
取代配置类的方式,在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
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="spring"/>
</beans>