spring-ioc装配
文章分文手动配置依赖(setter方法注入和构造函数注入)和byType及byName查找依赖
首先第一个手动配置依赖利用ClassPathXmlApplicationContext这个对象,非常普通的bean标签 setter方法注入和构造函数注入
<bean id="dao1" class="org.springframework.test.main.dao.impl.UserDaoImpl1"></bean>
<bean id="dao2" class="org.springframework.test.main.dao.impl.UserDaoImpl2"></bean>
<bean id="service" class="org.springframework.test.main.service.impl.UserServiceImpl">
<!-- service 依赖于 dao1-->
<!-- setter 方法注入 name 属性为 setter方法名首字母小写 ref 属性为 注入到UserServiceImpl的<bean id='dao1'-->
<!--<property name="dao11" ref="dao1"></property>-->
<!-- 构造方法注入 name 为构造方法中注入的类型名称 ref 为注入属性类型的名称-->
<constructor-arg name = "dao111" ref="dao1"></constructor-arg>
</bean>
public class UserServiceImpl implements UserService {
//setter 方法注入
// UserDao dao1;
// public void setDao11(UserDao dao1) {
// this.dao1 = dao1;
// }
//构造 方法注入
UserDao dao1;//注入属性类型名称
public UserServiceImpl(UserDao dao111){//构造方法中注入属性的类型名称
this.dao1 = dao111;
}
@Override
public void query() {
dao1.query();
System.out.println("service");
}
}
test测试
public class TestUserIoc {
public static void main(String[] args) {
//ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("spring.xml");
//UserServiceImpl service = (UserServiceImpl) cac.getBean("service");
AnnotationConfigApplicationContext cac = new AnnotationConfigApplicationContext(spring.class);
UserServiceImpl service = (UserServiceImpl) cac.getBean("service");
service.query();
}
}
再来看byType 和 byName的装配方式
1.byName 已经注释掉依赖。byName的装配方式默认为为setter方法首字母小写,就是未设置name属性直接匹配id
<bean id="dao1" class="org.springframework.test.main.dao.impl.UserDaoImpl1"></bean>
<bean id="dao2" class="org.springframework.test.main.dao.impl.UserDaoImpl2"></bean>
<bean id="service" class="org.springframework.test.main.service.impl.UserServiceImpl" autowire="byName">
<!-- service 依赖于 dao1-->
<!-- setter 方法注入 name 属性为 setter方法名首字母小写 ref 属性为 注入到UserServiceImpl的<bean id='dao1'-->
<!--<property name="dao" ref="dao1"></property>-->
<!-- 构造方法注入 -->
<!--<constructor-arg name="dao111" ref="dao1"></constructor-arg>-->
</bean>
public class UserServiceImpl implements UserService {
//setter 方法注入
// UserDao dao1;
// public void setDao(UserDao dao1) {
// this.dao1 = dao1;
// }
//构造 方法注入
// UserDao dao1;
// public UserServiceImpl(UserDao dao111){
// this.dao1 = dao111;
// }
//byName 自动装配
UserDao dao1;
public void setDao1(UserDao dao1) {//setDao1首字母小写 可以改位setDao123 需和xml文件中bean id匹配,与此处的UserDao dao1 属性名无关,可以自己更改验证
this.dao1 = dao1;
}
@Override
public void query() {
System.out.println("service");
dao1.query();
}
}
2.byType同样去掉依赖自动装配。byType是根据class的类型去装配的
<bean id="dao1" class="org.springframework.test.main.dao.impl.UserDaoImpl1"></bean>
<bean id="dao2" class="org.springframework.test.main.dao.impl.UserDaoImpl2"></bean>
<bean id="service" class="org.springframework.test.main.service.impl.UserServiceImpl" autowire="byType">
<!-- service 依赖于 dao1-->
<!-- setter 方法注入 name 属性为 setter方法名首字母小写 ref 属性为 注入到UserServiceImpl的<bean id='dao1'-->
<!--<property name="dao" ref="dao1"></property>-->
<!-- 构造方法注入 -->
<!--<constructor-arg name="dao111" ref="dao1"></constructor-arg>-->
</bean>
public class UserServiceImpl implements UserService {
//setter 方法注入
// UserDao dao1;
// public void setDao(UserDao dao1) {
// this.dao1 = dao1;
// }
//构造 方法注入
// UserDao dao1;
// public UserServiceImpl(UserDao dao111){
// this.dao1 = dao111;
// }
//byName 自动装配
// UserDao dao1;
// public void setDao1(UserDao dao1) {
// this.dao1 = dao1;
// }
//byType 自动装配
UserDao dao333;
public void setDao444(UserDao dao333) {//根据class的类型去自动装配 可以发现这种装配方式与属性名无关与setter方法名无关
this.dao333 = dao333;
}
@Override
public void query() {
System.out.println("service");
dao333.query();
}
}
我们可以测试一下是正常运行,但是如果将dao1和dao2类型这样改为同一个呢
<bean id="dao1" class="org.springframework.test.main.dao.impl.UserDaoImpl1"></bean>
<bean id="dao2" class="org.springframework.test.main.dao.impl.UserDaoImpl1"></bean>
<bean id="service" class="org.springframework.test.main.service.impl.UserServiceImpl" autowire="byType">
<!-- service 依赖于 dao1-->
<!-- setter 方法注入 name 属性为 setter方法名首字母小写 ref 属性为 注入到UserServiceImpl的<bean id='dao1'-->
<!--<property name="dao" ref="dao1"></property>-->
<!-- 构造方法注入 -->
<!--<constructor-arg name="dao111" ref="dao1"></constructor-arg>-->
</bean>
错误也很明显,我需要一个,但是匹配到了两个
除了改位byName以外,怎么样可以避免这类问题出现呢?下面结合了spring Annotation方式来验证
使用注解可以测试到@Autowired默认使用byType装配,@Resource默认使用byName(这儿的byName见下面解释)装配。到底是哪个注解次选byType装配后期验证
第一种组合注解使用指定一个具体的实现类
//byType 自动装配
@Autowired
@Qualifier(value = "userDaoImpl1")
UserDao dao;
public void setDao(UserDao dao) {//根据class的类型去自动装配 可以发现这种装配方式与属性名无关与setter方法名无关
this.dao = dao;
}
第二种组合注解@Primary也指定一个具体的实现类
//byType 自动装配
@Autowired
UserDao dao;
public void setDao(UserDao dao) {//根据class的类型去自动装配 可以发现这种装配方式与属性名无关与setter方法名无关
this.dao = dao;
}
@Component
@Primary
public class UserDaoImpl2 implements UserDao {
@Override
public void query() {
System.out.println("dao2");
}
}
第三种使用@Resource注解,由上述代码运行后可以看到@Resource默认是使用byName,需要注意的是这个地方的byName的装配到的是属性名,与方法名无关。
@Resource
UserDao userDaoImpl1;
public void setUserDaoImpl99999(UserDao dao) {//这儿默认是使用byName的装配方式,但这儿的byName匹配到的是属性名。与方法名无关
this.userDaoImpl1 = dao;
}
@Override
public void query() {
System.out.println("service");
userDaoImpl1.query();
}
下面这种运行可以得到如果注解中有属性值,则以注解内的值为准,打印为dao2
@Resource(name = "userDaoImpl2")
UserDao userDaoImpl1;
public void setUserDaoImpl99999(UserDao dao) {//这儿默认是使用byName的装配方式,但这儿的byName匹配到的是属性名。与方法名无关
this.userDaoImpl1 = dao;
}
@Override
public void query() {
System.out.println("service");
userDaoImpl1.query();
}
接下来看看@Resource注解的type属性,我们如果按照下面的装配形式运行,肯定是会报错的。要么将@Resource(type = UserDaoImpl2.class)改为@Resource(type = UserDaoImpl1.class) 或者将UserDao userDaoImpl1改为UserDao userDaoImpl2一一对应即可成功。所以综上所述@Resource装配是类型默认以byName。但是这儿的byName又是以属性名装配的。
@Resource(type = UserDaoImpl2.class)
UserDao userDaoImpl1;
public void setUserDaoImpl99999(UserDao dao) {//这儿默认是使用byName的装配方式,但这儿的byName匹配到的是属性名。与方法名无关
this.userDaoImpl1 = dao;
}
@Override
public void query() {
System.out.println("service");
userDaoImpl1.query();
}
下篇请看代码解析ioc的装配