Spring中Bean的装配方式以及常见问题

在确保可运行项目能够正确无误地运行之后,再严格照着教程的步骤,对代码模仿一遍。模仿过程难免代码有出入,导致无法得到期望的运行结果,此时此刻通过比较正确答案 ( 可运行项目 ) 和自己的代码,来定位问题所在。采用这种方式,学习有效果,排错有效率,可以较为明显地提升学习速度,跨过学习路上的各个槛。

源代码:

链接:https://pan.baidu.com/s/1mLbZ6C-qk1Jhj44PZPgOBQ?pwd=82q9
提取码:82q9

一.基于XML的装配:

Spring 提供了两种基于 XML 的装配方式:设值注入(Setter Injection)和构造注入 (Constructor
Injection)。下面讲解如何在XML 配置文件中使用这两种注入方式来实现基于 XML 的装配。在 Spring 实例化 Bean 的过程中,Spring 首先会调用 Bean 的默认构造方法来实例化 Bean 对象,然后通过反射的方式调用 setter()方法来注入属性值。因此,设值注入要求一个 Bean 必须满足以下两点要求:

  • Bean 类必须提供一个默认的无参构造方法
  • Bean 类必须为需要注入的属性提供对应的setter()方法。

使用设值注入时,在Spring 配置文件中需要使用<bean>元素的子元素<property>来为每个属性注入值;而使用构造注入时,在配置文件中需要使用<bean>元素的子元素<constructor-arg>来定义构造方法的参数,可以使用其value 属性(或子元素)来设置该参数的值。

案例:

1.创建一个动态web项目命名为chapter02,在src目录下创建一个包命名为assemble,创建User类,并在类中定义userName,password和list集合3个属性及对应的setter()方法。

package assemble;

import java.util.List;

public class User {
private String userName;
private String password;
private List<String> list;
public  User(String userName,String password,List<String> list) {
	super();
	this.userName=userName;
	this.password=password;
	this.list=list;
}
public String toString() {
	return "User:"+ userName+" "+password+" "+list;
}
public User() {
	super();
}
public void setUserName(String userName) {
	this.userName=userName;
}
public void setPassword(String password) {
	this.password=password;
}
public void setList(List<String> list) {
	this.list=list;
}
}

2.在src目录下创建applicationContext.xml文件,增加通过构造注入和设值注入方法装配User实例的两个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="user1" class="assemble.User">
   <constructor-arg index="0" value="zhang_san"></constructor-arg>
   <constructor-arg index="1" value="1111111"></constructor-arg>
   <constructor-arg index="2" >
   <list>
   <value>"constructorValue1" </value>
   <value>"constructorValue2" </value>
   </list>
   </constructor-arg>
   </bean>
   
   <bean id="user2" class="assemble.User">
   <property name="userName" value="li_si"></property>
   <property name="password" value="66666"></property>
   <property name="list" >
   <list>
   <value>"listValue1"</value>
   <value>"listValue2"</value>
   </list>
   </property>
   </bean>
   </beans>

在上述代码中,<constructor-arg>元素用于定义构造方法的参数,其属性 index 表示其索引(从0开始),value 属性用于设置注入的值,其子元素<list>为 User 类中对应的 list 集合属性注人值。然后又使用设值注入方法裝配 User 类的实例,其中<property>元素用于调用Bean 实例中的setter()方法完成属性赋值,从而完成依赖注入,而其子元素<list>同样为 User 类中对应的 list 集合属性注入值。

3.在assemble包中创建测试类XmlAssembleTest,在类中分别获取并输出配置文件中的user1和user2实例

package assemble;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XMLAssembleTest {
public static void main(String[] args) {
	ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
	System.out.println(applicationContext.getBean("user1"));
	System.out.println(applicationContext.getBean("user2"));
}
}

运行结果如下:

 二.基于Annotation的装配

在 Spring 中,尽管使用 XML 配置文件可以实现 Bean 的装配工作,但如果应用中有很多 Bean,
就会导致 XML 配置文件过于臃肿,给以后的维护和升级工作带来一定的困难。为此,Spring提供
了对 Annotation(注解)技术的全面支持。

Spring的常用注解
注解名称说明
@Repository用于将数据访问层的类标识为Spring中的Bean,其功能与@Component相同
@Service通常用作在业务层,用于将业务层的类标识为Spring中的Bean,其功能与@Component相同
@Controller通常用在控制层,用于将控制层的类标识为Spring中的Bean,其功能与@Component相同
@Autowired用于对Bean的属性变量。属性的setter()方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动配置工作。默认按照Bean的类型进行装配
@Resource其作用与@Autowired 一样,区别在于@Autowired 默认按 Bean 类型装配,而@Resource
默认按照 Bean 实例名称进行装配。@Resource 中有两个重要属性:name 和 type。 Spring
将name 属性解析为 Bean 实例名称,type属性解析为 Bean 实例类型。若指定 name 属性则按实例名称进行装配;若指定 type属性,则按 Bean 类型进行装配;若都不指定,则先按 Bean 实例名称装配,不能匹配时 再按照 Bean 类型进行装配:若都无法匹配,则抛出
NoSuchBeanDefinitionException 异常
@Qualifier与@Autowired注解配合使用,会默认的按Bean类型装配修改为Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定
@Component可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件,并且可以作用在任何层次。使用时只需要将该注解标注在相应的类上即可。

案例

1.在chapter02项目的src目录下创建一个annotation包,在该包中创建接口UserDao,并在接口中定义一个save()方法

package annotation;

public interface UserDao {
public void save() ;
}

2.在annotation包下创建UserDaoImpl类实现接口UserDao中的save()方法。

package annotation;

import org.springframework.stereotype.Repository;
@Repository("userDao")
//使用@Repository注解将UserDaoImpl类标识为Spring中的Bean
public class UserDaoImpl implements UserDao{
	public void save() {
		// TODO Auto-generated method stub
		System.out.println("userDao.save()");
	}

}

3.在annotation包下创建接口UserService接口,在接口中定义一个save()方法。

package annotation;

public interface UserService {
public void save() ;

}

4.在annotation包下创建一个UserServiceImpl类实现UserService接口的save()方法。

package annotation;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService{
@Resource(name="userDao")
//相当于配置文件中<property name="userDao" ref="userDao"/>的写法
private UserDao userDao;
	public void save() {
		// TODO Auto-generated method stub
		this.userDao.save();
		System.out.println("执行userService.save()");
	}

}

5.在Annotation包下创建UserController类,

package annotation;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;

@Controller("userController")
public class UserController {
	@Resource(name = "userService")
	private UserService userService;


public void save() {
	this.userService.save();
	System.out.println("运行userController.save()");
}

}

6.在src目录创建beans1.xml文件用于编写基于Annotation装配的代码

<?xml version="1.0" encoding="UTF-8"?>
 <!-- 添加
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
  -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    
    
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    
    
    xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   
   
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/context      
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
   <!-- 使用context命名空间在配置文件上开启相应的注解处理器 -->
  <context:annotation-config/>
  
  <bean id="userDao" class="annotation.UserDaoImpl"></bean>
  <bean id="userService" class="annotation.UserServiceImpl"></bean>
  <bean id="userController" class="annotation.UserController"></bean>
</beans>
   

在< beans>元素中增加包含context 的约束信息:然后通过配置<context: annotation-config/>来开启注解处理器:最后分别定义了了个Bean 对应的3个实例。与XML 配置方式有所不同的是,这里不再要配置子元素<property>。

 上述Spring 配置文件中的注解方式虽然较大程度地简化了 XML 文件甲 Bean 的配置,但仍需在Spring 配置文件中配置相应的 Bean,为此 Spring 注解提供了 另一种高效的注解配置方式(对包路径下的所有 Bean 文件进行扫描),其配置方式如下(beans2.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" 
    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/aop 
   http://www.springframework.org/schema/aop/spring-aop.xsd
   http://www.springframework.org/schema/tx 
   http://www.springframework.org/schema/tx/spring-tx.xsd
   http://www.springframework.org/schema/context      
   http://www.springframework.org/schema/context/spring-context.xsd">
   <!-- jdk使用1.5版本 -->
   <context:component-scan base-package="annotation"></context:component-scan>
</beans>
   

 Spring 4.0 以上版本使用上面的代码对指定包中的注解进行扫描前需要先向项目中导入Spring AOP 的 JAR 包spring-aop-5.2.5.RELEASE.jar,否则程序在运行时会报出:

”java.lang. NoClassDefFoundError:org/springframe work/aop/ TargetSource“错误。

在使用beans2.xml配置文件时jdk最高支持1.5版本,否则会报出:

“Unsupported class file major version 61”错误。

7.在annotation包下创建AnnotationAssembleTest类,在类中编写测试方法并定义配置文件的路径,然后通过Spring容器加载配置文件并获取UserController实例,最后调用实例中的save()方法。

package annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AnnotationAssembleTest {
public static void main(String[] args) {
	ApplicationContext applicationContext1=new ClassPathXmlApplicationContext("beans1.xml");
	UserController userController1=(UserController) applicationContext1.getBean("userController");
	userController1.save(); 
	
	ApplicationContext applicationContext2=new ClassPathXmlApplicationContext("beans2.xml");
	UserController userController2=(UserController) applicationContext2.getBean("userController");
	userController2.save();
}
}

运行结果:

 三.自动装配

虽然使用注解的方式装配 Bean 在一定程度上減少了配置文件中的代码量,但是也有企业项目是没有使用注解方式开发的,那么有没有什么办法既可以减少代码量,又能够实现 Bean 的装配呢?
答案是肯定的。Spring 的<bean>元素中包含一个autowire 厲性,我们可以通过设置 autowire 的属性值来自动装配 Bean。 所谓自动装配,就是将一个 Bean 自动注入其他 Bean 的 Property 中。

案例:

1.在annotation包中创建类AutoUserServiceImpl类设置setter()方法。

package annotation;

public class AutoUserServiceImpl implements UserService{

	private UserDao userDao;
	public void setUserDao(UserDao userDao) {
		this.userDao=userDao;
	}
	public void save() {
		// TODO Auto-generated method stub
		this.userDao.save();
		System.out.println("执行userService.save()");
	}

}

2.在annotation包中创建类AutoUserController类设置setter()方法。

package annotation;

public class AutoUserController {
	private UserService userService;
	public void setUserService(UserService userService) {
		this.userService=userService;
	}

public void save() {
	this.userService.save();
	System.out.println("运行userController.save()");
}
}

3.创建beans3.xml文件,将<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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/aop 
   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
   http://www.springframework.org/schema/context      
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  <context:annotation-config/>
  
  <bean id="userDao" class="annotation.UserDaoImpl"></bean>
  <bean id="userService" class="annotation.UserServiceImpl" autowire="byName"></bean>
  <bean id="userController" class="annotation.UserController" autowire="byName"></bean>
</beans>
   

在上述配置文件中,用于配置userService和userController的<bean>元素中除了id和class属性外,还增加了autowire 属性,并将其属性值设置为 byName。在默认情况下,配置文件中需要通过ref 来装配 Bean, 但设置了autowire="byName"后,Spring 会自动寻找userServiceBean 中的属性将其属性名称与配置文件中定义的 Bean 做匹配。由于 UserServicelmpl中定义了 userDao属性及其setter()方法,这与配置文件中 id 为 userDao 的 Bean 相匹配,因此 Spring 会自动地将 id 为 userDao的 Bean 装配到 id 为userService 的 Bean 中。

 运行结果:

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无忧#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值