SpringIOC随笔(六)-依赖注入(DI)
SpringIOC随笔(六)-依赖注入(DI)
- DI(Dependency Injection)
- 概念:对象之间的关系的装配交给容器来管理。
注入的方式:
构造注入:
- 顾名思义,构造注入就是使用构造方法注入,所以使用构造注入肯定要写对应的构造方法。下面直接上例子:
public class User implements Serializable {
private static final long serialVersionUID = 84601116866236075L;private String username;
private String password;
private Department department;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User(String username, String password, Department department) {
this.username = username;
this.password = password;
this.department = department;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", department=" + department +
'}';
}
}
public class Department implements Serializable {
private static final long serialVersionUID = -7390074405145933835L;private Integer id;
private String departmentName;
private String address;
public Department() {
}
public Department(Integer id, String departmentName, String address) {
this.id = id;
this.departmentName = departmentName;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Department{" +
"id=" + id +
", departmentName='" + departmentName + '\'' +
", address='" + address + '\'' +
'}';
}
}
3.
```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 id="user" class="com.fxyh.spring.di.User">
<constructor-arg index="0" value="zhangsan"/>
<constructor-arg index="1" value="123456"/>
<!--ref方式-->
<!--<constructor-arg index="2" ref="department"/>-->
<constructor-arg index="2">
<!--内部bean方式-->
<bean class="com.fxyh.spring.di.Department">
<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="Ali"/>
<constructor-arg index="2" value="hangzhou"/>
</bean>
</constructor-arg>
</bean>
<bean id="department" class="com.fxyh.spring.di.Department">
<constructor-arg index="0" value="1"/>
<constructor-arg index="1" value="Baidu"/>
<constructor-arg index="2" value="shengzhen"/>
</bean>
</beans>
- @ContextConfiguration(“classpath*:applicationContext-di.xml”)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserTest {
@Autowired
private User user;
@Test
public void test() {
System.out.println(this.user);
}
}
2. 这里使用的是Spring-test,然后省去了很多代码。
* <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.21.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2. ### setter注入 ###
1. 使用setXxx方法注入的方式,这里不提了。
3. ### 集合注入 ###
1. array,list,set,map,properties注入。
2. <bean id="collectionDemo" class="com.fxyh.spring.di.CollectionDemo">
<property name="arrayValue">
<array>
<value>zhangsan</value>
<value>lisi</value>
<value>wangwu</value>
</array>
</property>
<property name="listValue">
<list>
<value>beijin</value>
<value>shanghai</value>
<value>hangzhou</value>
<value>shenzhen</value>
</list>
</property>
<property name="setValue">
<set>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
<value>ddd</value>
</set>
</property>
<property name="mapValue">
<map>
<entry key="key1" value="111"/>
<entry key="key2" value="222"/>
<entry key="key3" value="333"/>
<entry key="key4" value="444"/>
</map>
</property>
<property name="properties">
<props>
<prop key="driverClassName">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql:///fxyh</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
3. public class CollectionDemo implements Serializable {
private static final long serialVersionUID = -4477381744799533624L;
private String[] arrayValue;
private List<String> listValue;
private Set<String> setValue;
private Map<String, Object> mapValue;
private Properties properties;
public String[] getArrayValue() {
return arrayValue;
}
public void setArrayValue(String[] arrayValue) {
this.arrayValue = arrayValue;
}
public List<String> getListValue() {
return listValue;
}
public void setListValue(List<String> listValue) {
this.listValue = listValue;
}
public Set<String> getSetValue() {
return setValue;
}
public void setSetValue(Set<String> setValue) {
this.setValue = setValue;
}
public Map<String, Object> getMapValue() {
return mapValue;
}
public void setMapValue(Map<String, Object> mapValue) {
this.mapValue = mapValue;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "CollectionDemo{" +
"arrayValue=" + Arrays.toString(arrayValue) +
", listValue=" + listValue +
", setValue=" + setValue +
", mapValue=" + mapValue +
", properties=" + properties +
'}';
}
}
4. ### 抽象Bean ###
1. 把公共的东西抽象出来,然后需要用到的使用parent。
2. <bean id="abstractDemo" abstract="true">
<property name="id" value="1"/>
<property name="username" value="zhangsan"/>
</bean>
<bean id="abstractDemo1" class="com.fxyh.spring.di.AbstractDemo1" parent="abstractDemo">
<property name="password" value="123456"/>
</bean>
<bean id="abstractDemo2" class="com.fxyh.spring.di.AbstractDemo2" parent="abstractDemo">
<property name="age" value="22"/>
</bean>
<bean id="abstractDemo3" class="com.fxyh.spring.di.AbstractDemo3" parent="abstractDemo">
<property name="address" value="jiangxi"/>
<property name="id" value="2"/>
</bean>
3. 这里abstractDemo是抽象Bean,然后使用parent对应这个则对应的属性就会被赋值,并且在自己的bean中重新给这个属性赋值了,那么这个属性将会把抽象bean中的属性的值给覆盖掉。
5. ### 自定义属性编辑器 ###
1. `no matching editors or conversion strategy found`
2. 比如我注入的时候注入时间,我直接写字符串的时间,然后这肯定是会报错的,就上面说的那个错误,无法注入。
3. 所以我们需要自定义属性编辑器。
4. import org.apache.commons.lang3.time.DateUtils;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;
public class CustomDatePropertyEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
Date date = null;
try {
date = DateUtils.parseDate(text, "yyyy-MM-dd");
} catch (ParseException e) {
e.printStackTrace();
}
this.setValue(date);
}
}
5. <bean id="person" class="com.fxyh.spring.di.Person">
<property name="id" value="1"/>
<property name="username" value="zhangsan"/>
<property name="salary" value="#{10*new java.util.Random().nextInt(10)}"/>
<property name="createDate" value="2019-06-30"/>
</bean>
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="com.fxyh.spring.di.CustomDatePropertyEditor"/>
</map>
</property>
</bean>
6. 自定义属性编辑器我们需要继承PropertyEditorSupport类,然后重写它的setAsText方法。现在已经不推荐使用了,推荐使用自定义转换器。
6. ### 自定义转换器 ###
1. 实现Converter接口,注意:`org.springframework.core.convert.converter.Converter`包路径。
2. 然后实现convert方法,在里面写对应的逻辑。
3. import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.util.Date;
public class CustomDateConverter implements Converter<String, Date> {
private String[] parsePatterns;
public void setParsePatterns(String[] parsePatterns) {
this.parsePatterns = parsePatterns;
}
@Override
public Date convert(String source) {
Date date = null;
if (StringUtils.isBlank(source)){
throw new IllegalArgumentException("");
}
try {
date = DateUtils.parseDate(source, this.parsePatterns);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
4. <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.fxyh.spring.di.CustomDateConverter">
<property name="parsePatterns">
<array>
<value>yyyy-MM-dd</value>
<value>yyyy/MM/dd</value>
</array>
</property>
</bean>
</set>
</property>
</bean>
5. 这里注意这个转换器bean的id,我用其他的试都是没用,只有把id改成conversionService才能使用。
ByName&ByType
- ByName:根据名称匹配
- ByType:根据类型匹配
- 这里有个比较经典的异常
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.fxyh.spring.dao.UserDao' available: expected single matching bean but found 2: userDao111111,userDao
- 这个接口有两个实现类,然后现在spring不知道选择哪个实现类注入就报这个异常了。
<?xml version=”1.0” encoding=”UTF-8”?>
- 这里在beans上使用了default-autowire为byType,所以这个beans下的bean都会根据类型自动注入,而此时有userDao和userDao111111都是实现了UserDao接口,所以两个都符合要求,然后bean就不知道要注入哪一个了,而这里我们又在userService配置了autowire为byName,此时userService是根据名称来匹配的,则只有userDao一个匹配成功。(这里提供setter方法,然后把setter方法set去掉,然后第一个字母小写,就是名称)
- 同时在配置中局部配置优先于全局配置!
注解编程
@Autowired
- 属于Spring框架的注解
- 先按类型匹配,如果匹配不到再按名称匹配
@Resource
- 属于JavaEE规范的注解
- 先按名称匹配,如果匹配不到再按类型匹配
@Qualifier
- 和@Autowired结合使用的时候,按照类型匹配,不按类型匹配。
- @Resource原本就是按名称所以在它按名称找不到的时候,使用@Qualifier设置的名称匹配。
@Component
- 把这个类注解为一个组件
@Repository
- 数据库交互层使用的注解(Dao)
@Service
- 服务层使用的注解
@Controller
- 控制层使用的注解
@Configuration
- 配置类注解
@Bean
- 把这个方法注解成一个创建bean的方法。
使用注解开发首先不能少了组件扫描,开启开关。
<?xml version=”1.0” encoding=”UTF-8”?>
- 这里不贴测试用例了,自己写写测试用例测一测就ok了。
还没有评论,来说两句吧...