3.17 Spring002

今天学的是Spring框架里的控制反转依赖注入

一、控制反转

IOC: Inversion of Control控制反转不是什么技术,而是一种设计思想,其作用是实例化具体的bean,动态装配bean。

  1. 类的一些属性: (例如UserService中的userDao成员属性)是由当前类(UserService)自己控制其实例化,现在不是由当前类(UserService)自己控制。现在Spring是利用接口来控制的。由原来控制实现转为spring现在来控制接口(向上反转).
  2. 我们可以使用xml或者注解来进行相关配置,spring会根据配置和约定,对对象进行实例化和属性装配。

DI:Dependency Injection依赖注入:一些成员属性(例如UserService中的userDao成员属性) 依赖Spring容器来注入,组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中

好处:是spring的核心机制,可以使Spring的bean以配置文件组织在一起,而不是硬编码方式耦合,耦合性相对来降低了;另外,注入是使用配置文件来实现,这样修改来非常的方便。

 

依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同IOC是说不需要程序员管理和控制bean,是解耦的目的DI是手段。IOC是指让生成类的方式由传统方式(new)反过来,既程序员不调用new,需要类的时候由Spring等框架注入(DI)

相关代码:

Spring中可以使用beanFactory的方法getBean获取指定对象的时候,常见的方法有几种?有什么不同?

1.Object getBean(String name) 根据名称返回一个Bean,客户端需要自己进行类型转换;

参数name可以是bean的属性id的值或者是name的值。

2.T getBean(String name, Class<T> requiredType) 根据名称和指定的类型返回一个Bean,客户端无需自己进行类型转换,如果类型转换失败,容器抛出异常;

3.T getBean(Class<T> requiredType) 根据指定的类型返回一个Bean,客户端无需自己进行类型转换,如果没有或有多于一个Bean存在容器将抛出异常;

二、bean的标识以及声明

1.一般配置文件结构如下:

<beans>
    <!--引用外部的配置文件,<import>标签可以放在<beans>下的任何位置,没有顺序关系 -->
    <import resource=”resource1.xml”/>
    <!-- class相同的情况下,context.getBean(bean里的id,类名.class)通过id来区分所初始化的对象 -->
    <bean id=”bean1” class=””></bean>
    <bean id=”bean2” class=””></bean>
    <!--<bean>标签主要用来进行Bean定义 -->
    <!--
标签中的属性id与name作用是一样,区别在于id中不可以含有特殊字符,
而name中可以有特殊字符;
id是确定该bean的唯一属性,而name可以指定一个或者多个名称,各个名称之间用逗号或分号分开。后面的为bean的别名。 
-->
<bean name=”bean2” class=””></bean>
    <!-- alias用于定义Bean别名的,如果添加了别名,可以用别名,也可以用之前的名字获取到这个对象-->
    <alias alias="bean3" name="bean2"/>
    <import resource=“resource2.xml”/>
</beans>

2.Bean命名约定:Bean的命名遵循XML命名规范,但最好符合Java命名规范,由“字母、数字、下划线组成”,而且应该养成一个良好的命名习惯, 比如采用“驼峰式”,即第一个单词首字母开始,从第二个单词开始首字母大写开始,这样可以增加可读性。

3.Bean的加载

默认情况下,我们使用:

ApplicationContext context=new ClassPathXmlApplicationContext("ApplicationContext.xml");

Spring容器就会自动初始化所有的单例(bean scope="singleton")的bean;但是如果是<bean scope="prototype">则不会自动初始化,而是等使用(context.getBean)的时候才实例化;

我们对单例的对象,可以手动设置其 <bean lazy-init="true">来设置其延迟初始化。当然,前提是这个对象没有被其他的bean引用。

 

三、注入方法(setter,constructor,接口注入等)

 1.setter注入类型

简言之,就是在bean中使用setXX方法进行注入。

点击name的赋值发现 其其对应的是public void setXxxx方法。

package com.etc.entity;
/** 
 * @author hyy
 * @ClassName:类名
 * @Description:描述  
 * @date 2022年3月15日 上午11:15:56 
 * @parameter 参数及其意义  
 * @return 返回值  
 */
public class Users {
	private int userid;
	private String username;
	private String userpass;
	
	public Users() {
		// TODO Auto-generated constructor stub
		System.out.println("无参数构造");
	}

	public int getUserid() {
		return userid;
	}

	public void setUserid(int userid) {
		this.userid = userid;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getUserpass() {
		return userpass;
	}

	public void setUserpass(String userpass) {
		this.userpass = userpass;
	}

	public Users(int userid, String username, String userpass) {
		super();
		this.userid = userid;
		this.username = username;
		this.userpass = userpass;
		System.out.println("带参数构造");
	}

	@Override
	public String toString() {
		return "Users [userid=" + userid + ", username=" + username + ", userpass=" + userpass + "]";
	}
}

配置文件代码:

<?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:cache="http://www.springframework.org/schema/cache"
	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-4.3.xsd
		http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd">

<bean class="com.etc.entity.Blog" id="blog"></bean>

<!-- 点击name的赋值发现 其其对应的是public void setXxxx方法 -->
<bean id="users1" class="com.etc.entity.Users">
<property name="userid" value="1"></property>
<property name="username" value="张三"></property>
<property name="userpass" value="123456"></property>
</bean>

<bean id="users2" class="com.etc.entity.Users">
<property name="userid" value="2"></property>
<property name="username" value="李四"></property>
<property name="userpass" value="789"></property>
</bean>


<bean id="usersdao" class="com.etc.dao.UsersDao">
 <!-- 给users对象赋值 注入 -->
<property name="users" ref="users2"></property>
</bean>

<!-- 创建UsersService的bean -->

<bean name="us1" class="com.etc.service.UsersService">
<property name="usersdao" ref="usersdao"></property>
</bean>

<bean name="us2" class="com.etc.service.UsersService">
<property name="usersdao" ref="usersdao"></property>
</bean>

<!-- 引用外部的配置文件 -->
<import resource="application1.xml"/>

</beans>

2.构造方法注入

bean类中需要有成员属性作为参数的构造方法

Spring配置文件:

<?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-4.3.xsd">

<bean id="u" name="u" class="com.etc.entity.Users" scope="prototype">
<!-- 第一种形式:给属性赋值 value注入字面值 -->
<property name="userid" value="1"></property>
<property name="username" value="admin"></property>
<property name="userpass" value="123456"></property>
</bean>


	<bean id="u1" name="u1" class="com.etc.entity.Users" scope="prototype">
		<!-- 通过构造来做注入,可以通过下方的beans按钮创建 -->
		<constructor-arg value="2"></constructor-arg>
		<constructor-arg value="adam"></constructor-arg>
		<constructor-arg value="999666"></constructor-arg>
	</bean>
	
	<bean id="u2" name="u2" class="com.etc.entity.Users" scope="prototype">
		<constructor-arg name="userid" value="3"></constructor-arg>
		<constructor-arg name="username" value="john"></constructor-arg>
		<constructor-arg name="userpass" value="666999"></constructor-arg>
	</bean>
</beans>

测试类:

package com.etc.test;

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

import com.etc.entity.Users;

/** 
 * @author hyy
 * @ClassName:类名
 * @Description:描述  
 * @date 2022年3月15日 上午11:15:56 
 * @parameter 参数及其意义  
 * @return 返回值  
 */
public class TestUsers {

	public static void main(String[] args) {
		ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
		Users u=context.getBean("u",Users.class);
		System.out.println(u);
		
		Users u1=context.getBean("u1", Users.class);
		System.out.println(u1);
		Users u2=context.getBean("u2", Users.class);
		System.out.println(u2);
	}
}

四、注入类型

1. 简单属性的注入

当bean中存在简单属性时的注入方式:

<bean id="u" class="com.hyy.entity.Users">
		<property name="name" value="小白" />
		<property name="id">
		   <value>123</value>
		</property>
	</bean>

2.Spring不仅能注入简单类型数据,还能注入集合(Collection、无序集合Set、有序集合List)类型、数组(Array)类型、字典(Map)类型数据、Properties类型数据。

<!-- 是定义一个bean -->
	<bean id="le" class="com.hyy.entity.ListEntity">
		<!-- 属性注入方式  list set... -->
		<property name="list">
			<list>
				<value>1</value>
				<value>hyy</value>
				<value>23.45</value>
			</list>
		</property>

		<!-- map方式 -->
		<property name="map">
			<map>
				<entry key="1" value="老华"></entry>
				<entry key="2" value="小华"></entry>
				<entry key="3" value="代你飞"></entry>
			</map>
		</property>
	</bean>

如果是引用类型(对象的实例),用ref:

Map的写法(key为基本数据类型,value为对象,用value-ref引用):

注入自定义类型对象:

注入小结:

注入方法:

1、构造方法注入:

1)常量值

简写:<constructor-arg index="0" value="常量"/>

全写:<constructor-arg index="0"><value>常量</value></constructor-arg>

2)引用

简写:<constructor-arg index="0" ref="引用"/>

全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>

2、setter注入:  

     1)常量值

     简写:<property name="message" value="常量"/>

     全写:<property name="message"><value>常量</value></ property>

    2)引用

     简写:<property name="message" ref="引用"/>

     全写:<property name="message"><ref bean="引用"/></ property>

注入类型:

     1)数组:<array> 了解

     2)列表:<list>  了解

     3)集合:<set>   了解

     4)字典    了解

简写:<map>

             <entry key="键常量" value="值常量"/>

             <entry key-ref="键引用" value-ref="值引用"/>

            </map>

全写:      <map>

             <entry><key><value>键常量</value></key><value>值常量</value></entry>

             <entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>

           </map>

 

5)自定义类型的注入:引用定义好的bean

五、Bean的作用域

在面向对象程序设计中一般指对象或变量之间的可见范围。而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围

Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”、“session”、“global session”三种web作用域;Spring还允许用户定制自己的作用域

     利用<bean>标签中的scope属性来指定

scope值:

  • singleton单例:每次取出的bean都是同一个bean。默认就是这个。
  • prototype原型:每次取的bean时,都会重新创建一个新的bean ,是懒加载
  • request:一次请求一个bean定义对应一个实例(web相关)
  • session:一个session定义对应一个实例(web相关)
  • globalsession类似于session作用域,只是其用于portlet环境的web应用。如果在非portlet环境将视为session作用域(web相关)

六、自动装配autowire(由Spring来自动地注入依赖对象)

自动装配就是指由Spring来自动地注入依赖对象

     Spring的装配支持“no”、“byName ”、“byType”、“constructor”四种自动装配,默认是“no”指不支持自动装配的。

     自动装配的好处是减少构造器注入和setter注入配置,减少配置文件的长度。自动装配通过配置<bean>标签的“autowire”属性来改变自动装配方式。

     1、default:表示使用默认的自动装配,默认的自动装配需要在<beans>标签中使用default-autowire属性指定,其支持“no”、“byName ”、“byType”、“constructor”四种自动装配,如果需要覆盖默认自动装配,请继续往下看;

    2、no:意思是不支持自动装配,必须明确指定依赖。

    3、byType:按照类型来进行装配,但是要求同一个类型的bean在xml中只能有一个调用setter方法

    4、byName:通过设置Bean定义属性autowire="byName",意思是根据名字进行自动装配,只能用于setter注入。

七、Junit单元测试(主要分为Junit4和Junit5)

使用Junit完成简单的单元测试,在一个方法上增加一个注解:

@Test 注意大小写,同时要将junit5.jar添加到构建路径中来,再运行这个方法的时候,Run as Junt test,如果出现了绿色,表示单元测试成功,代码没有问题。

 

 

相关代码:

package com.etc.junit;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.etc.entity.ListEntity;

/** 
 * @author hyy
 * @ClassName:类名
 * @Description:加入了junit的测试代码
 * @date 2022年3月15日 上午11:15:56 
 * @parameter 参数及其意义  
 * @return 返回值  
 */
public class ListBean {
	ApplicationContext context;
	
	@Before
	public void before() {
		context = new ClassPathXmlApplicationContext("ListEntity.xml");
	}
	
	@Test
	public void test1() {
		ListEntity entity = context.getBean("le1", ListEntity.class);
		entity.getList().forEach(System.out::println);
	}
	
	@Test
	public void test2() {
		ListEntity entity2 = context.getBean("le2",ListEntity.class);
		entity2.getList().forEach(System.out::println);
	}
}

Spring+Junit test

首先,要添加spring-test.jar到构建路径;

编写测试类,使用注解来配合Junit4代码;

相关代码如下(Junit4两个注解:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/ListEntity.xml"})

Junit5一个注解:

@SpringJUnitConfig(locations = "classpath:xxxxx.xml")

Junit4 测试代码

package com.etc.junit;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.etc.entity.ListEntity;

/** 
 * @author hyy
 * @ClassName:类名
 * @Description:描述  
 * @date 2022年3月15日 上午11:15:56 
 * @parameter 参数及其意义  
 * @return 返回值  
 */

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/ListEntity.xml"})
public class ListBean2 {
	//自动装配
	@Autowired
	//如果有多个bean,需要通过@Qualifier来指定bean的id或者名称
	@Qualifier(value = "le1")
	ListEntity entity;
	
	//自动装配
	@Autowired
	//如果有多个bean,需要通过@Qualifier来指定bean的id或者名称
	@Qualifier(value = "le2")
	ListEntity entity2;
	
	@Test
	public void test1() {
		entity.getList().forEach(System.out::println);
	}
	
	@Test
	public void test2() {
		entity2.getList1().forEach(System.out::println);
	}
}

Junit5 测试代码

package com.etc.junit;

import javax.annotation.Resource;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

import com.etc.entity.ListEntity;

/** 
 * @author hyy
 * @ClassName:类名
 * @Description:描述  
 * @date 2022年3月15日 上午11:15:56 
 * @parameter 参数及其意义  
 * @return 返回值  
 */
@SpringJUnitConfig(locations = "classpath:ListEntity.xml")
public class TestListBean3 {
	//自动装配但是通过名字来装配
	@Resource(name = "le1")
	ListEntity entity;
	
	//自动装配
	@Autowired
	//如果有多个bean,需要通过@Qualifier来指定bean的id或者名称
	@Qualifier(value = "le2")
	ListEntity entity2;
	
	@Test
	public void test1() {
		entity.getList().forEach(System.out::println);
	}
	
	@Test
	public void test2() {
		entity2.getList1().forEach(System.out::println);
	}
}

 

posted on 2022-03-18 13:22  heyiyang1312  阅读(7)  评论(0)    收藏  举报

导航