昔洛 的个人博客

Bug不空,誓不成佛

  menu
70 文章
14633 浏览
1 当前访客
ღゝ◡╹)ノ❤️

第二篇 Spring 中的Bean (下)

基于XML的装配

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

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

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

1.新建一个项目导入需要的框架包并在src下建立一个com.cn.assemble包,在包中创建User类,并在类中定义username、password 和 list 集合三个属性以及对应的setter方法,代码如下

package com.cn.assemble;
import java.util.List;
public class User {
	private String username;
	private Integer password;
	private List<String> list;
	/*
	 * 1.使用构造注入
	 * 2.提供带所有参数的有参构造方法
	 */
	public User(String username, Integer password, List<String> list) {
		super();
		this.username = username;
		this.password = password;
		this.list = list;
	}
	/*
	 * 1.使用设值注入
	 * 2.提供默认空参构造方法
	 * 3.为所有属性设置setter方法
	 */
        public User() {
	}	
        public void setUsername(String username) {
		this.username = username;
	}
	public void setPassword(Integer password) {
		this.password = password;
	}
	public void setList(List<String> list) {
		this.list = list;
	}
	//重写toString()方法方便观察结果
	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + ", list=" + list + "]";
	}
}

2.在src下创建beans.xml,在配置文件中通过构造注入和设值注入的方式装配User类的实例,代码如下:

<?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="com.cn.assemble.User">
		<constructor-arg index="0" value="tom"/>
		<constructor-arg index="1" value="123456"/>
		<constructor-arg index="2" >
			<list>
				<value>"constructorvalue1"</value>
				<value>"constructorvalue2"</value>
			</list>
		</constructor-arg>
	</bean>
	<!-- 使用设值注入方式装配 -->
	<bean id="user2" class="com.cn.assemble.User">
		<property name="username" value="张三"></property>
		<property name="password" value="654321"></property>
		<!-- 注入list集合 -->
		<property name="list">
			<list>
				<value>"setlistvalue1"</value>
				<value>"setlistvalue2"</value>
			</list>
		</property>
		<!--如果是map类型就这样注入-->
		<!--
		<property name="authorsInfo"> 
		<map>		
			<entry key="1" value="Deepak" />		
			<entry key="2" value="Arun"/>		
			<entry key="3" value="Vijay" />		
		</map>		
		</property>
		-->
	</bean>
</beans>

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

3.创建测试类XmlBeanAssembleTest,在类中分别获取并输出配置文件中的user1和user2实例。代码如下:

package com.cn.assemble;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class XmlBeanAssembleTest {
	@Test
	public void Test() {
		ApplicationContext appc = new ClassPathXmlApplicationContext("beans.xml");
		System.out.println(appc.getBean("user1"));
		System.out.println(appc.getBean("user2"));
	}
}

运行结果如下所示:
image.png

基于Annotation的装配(注解方式,重点!)

Spring 中定义了一系列的注解,常用的注解方式如下:

  • @Component:可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应的类上即可。
  • @Repository:通常作用在业务层(DAO 层)的类标识为Spring中的Bean,其功能与@Component相同
  • @Service:通常作用在业务层(Service 层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同。
  • Controller:通常作用在控制层(如Spring MVC 的 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注解的参数指定

下面几步简单的例子演示注解的使用:
1.创建一个com.cn.annotation包,在包中创建接口UserDao,并在接口中定义一个save()方法,代码如下:

package com.cn.annotation;
public interface UserDao {
	public void save();
}

2.创建UserDao接口的实现类UserDaoImpl,并实现save()方法,代码如下:

package com.cn.annotation;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao{
	public void save() {
		System.out.println("userdao...save...");
	}
}	

首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,其写法相当于配置文件中<bean id="userDao" class="com.cn.annotation.UserDaoImpl"/>的编写。
3.创建接口UserService在接口中同样定义一个save()的方法,代码如下:

package com.cn.annotation;
public interface UserService {
	public void save();
}

4.创建UserService接口的实现类UserServiceImpl,该类需要实现接口中的save方法代码如下:

package com.cn.annotation;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

@Service("userService")
public class UserServiceImpl implements UserService{
	@Resource(name="userDao")
	private UserDao userDao;
	public void save() {
		this.userDao.save();
		System.out.println("userservice...save...");
	}
}

如上所示,首先使用@Service注解将UserServiceImpl类标识为Spring中的Bean,这相当于配置文件中<bean="userService" class="com.cn.annotation.UserServiceImpl"/>的编写;然后使用@Resource注解标注在属性userDao上,这相当于配置文件中<property name="userDao" ref="userDao"/>的写法。
5.创建控制器类UserController,编辑后如下所示:

package com.cn.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.创建配置文件AnnotationBean.xml,配置中编写基于Annotation装配的代码,如下:

<?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命名空间,在配置文件中开启相应的注解处理器 -->
        <context:annotation-config>
        	<!-- 分别定义3个Bean实例 -->
        	<bean id="userDao" class="com.cn.annotation.UserDaoImpl"/>
        	<bean id="userService" class="com.cn.annotation.UserServiceImpl"/>
        	<bean id="userController" class="com.cn.annotation.UserController"/>
        </context:annotation-config>
</beans>

上述Spring配置文件中的注解方式虽然较大程度简化了XML文件中Bean的配置,但仍需要在Spring配置文件中一一配置相应的Bean,为此Spring注解提供了另外一种高效的注解配置方式(对包路径下的所有Bean文件进行扫描),其配置如下:
<context:component-scan base-package="Bean 所在的包路径"/>
所以上述配置中<context:annotation-config></context:annotation-config>及其内容都可替换为<context:component-scan base-package="com.cn.annotation"/>(推荐使用这个)
注意:Spring 4.0以上版本使用上面的代码对指定包中的注解进行扫描时,需要先向项目中导入spring-aop-4.3.6.RELEASE.jar,否则程序在运行时会报错!
7.创建测试类AnnotationAssembleTest类,然后通过Spring容器加载配置文件获取UserController实例,最后调用示例中的save()方法,代码如下:

package com.cn.annotation;

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

public class AnnotationAssembleTest {
	@org.junit.Test
	public void Test() {
		ApplicationContext appc = new ClassPathXmlApplicationContext("AnnotationBean.xml");
		//获取UserController实例
		UserController userController = appc.getBean("userController",UserController.class);
		userController.save();
	}
}

运行结果如下:
image.png

自动装配

Spring的<bean>元素包含一个autowire属性,我们可以通过设置autowire属性值来自动装配Bean。所谓自动装配,就是将一个Bean自动地注入到其他Bean的Property中。
autowire属性有5个值,如下所示:

属性值说明
default(默认值)由<bean>的default-autowire 属性值确定。例如<beans default-autowire="byName">,则该<bean>元素中的autowire属性对应的属性值就为byName
byName根据属性的名称自动装配。容器将根据名称查找与属性完全一致的Bean,并将其属性自动装配
byType根据属性的数据类型(Type)自动装配,如果一个Bean的数据类型,兼容另一个Bean中属性的数据类型,则自动装配
constructor根据构造函数参数的数据类型,进行byType模式的自动装配
no在默认情况下,不使用自动装配,Bean依赖必须通过ref元素定义

下面简单几步演示如何自动装配
1.修改上面UserServiceImpl文件和UserController,分别在文件中增加雷属性的setter()方法
2.修改配置文件AnnotationBean.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">
       <!-- 使用bean元素的autowire属性完成自动装配 -->
       <bean id="userDao" class="com.cn.annotation.UserDaoImpl"/>
       <bean id="userService" class="com.cn.annotation.UserServiceImpl" autowire="byName"/>
       <bean id="userController" class="com.cn.annotation.UserController" autowire="byName"/>
</beans>

在默认情况下,配置文件中需要通过ref来装配Bean,但设置autowire="byName"后,Spring会自动寻找userServiceBean中的属性,并将其属性名称与配置文件中定义的Bean做匹配,由于UserServiceImpl中定义了userDao属性及其setter方法,这与配置文件中id为userDao的Bean相匹配,所以Spring会自动地将id为userDao的Bean装配到id为userService的Bean中。
运行结果如下图所示:
image.png

希望所有的 Bug 都会报错~