超全的SpringIOC和DI实践

文章目录

      • 一、配置SpringIOC容器
      • 二、基于XML的配置方式
        • (1)构造器和setter属性的注入
        • (2)集合类型setter属性的注入
      • 三、基于注解的配置方式
      • 四、获取IOC容器的方式

这里的环境是在史上超详细的SpringMVC框架搭建基础上搭建的,如有不懂之处,望请参考。

一、配置SpringIOC容器

在web项目中配置Spring的Ioc容器其实就是创建web应用的上下文

在web.xml配置springIOC容器

  
  <context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:config/spring-context.xmlparam-value>
  context-param>
  
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
  listener> 

在src下config包里创建spring-context.xml,并进行一些命名空间的配置


<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-3.2.xsd">
		
beans>

二、基于XML的配置方式

DI依赖注入,有构造器注入和setter注入两种方式

创建User类和Address类作为Bean

public class User {
	private String name;
	private Address address;
	private String[] books;
	private List<String> courses;
	private Map<String,String> cards;
	private Set<String> games;
	private Properties properties;
	public User(String name,Address address){
		this.name=name;
		this.address=address;
	}
	//由于篇幅原因,setter方法省略
}
public class Address {
	private String name;

	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Address [name=" +name + "]";
	}
}

(1)构造器和setter属性的注入

	
	
	<bean id="address" class="com.my.model.Address">
	<property name="name" value="洛阳市"/>
	bean>
	
	
	
	<bean id="user" class="com.my.model.User">
	<constructor-arg name="name" value="王雷">constructor-arg>
	<constructor-arg name="address" ref="address">constructor-arg>
	bean>

(2)集合类型setter属性的注入

<bean id="myuser" class="com.my.model.User">
		<property name="name" value="王雷">property>
		
		<property name="books">
			<array>
				<value>小白书value>
				<value>白皮书value>
				<value>小红书value>
			array>
		property>
		
		<property name="courses">
			<list>
				<value>java从入门到精通value>
				<value>java从精通到精辟value>
			list>
		property>
		
		<property name="cards">
			<map>
				<entry>
					<key><value>ICBCvalue>key>
					<value>工商银行value>
				entry>
				<entry key="ABC">
					<value>农业银行value>
				entry>
			map>
		property>
		
		<property name="games">
			<set>
				<value>王者荣耀value>
				<value>LOLvalue>
				<value>dotavalue>
			set>
		property>
		
		
		
		<property name="wife"><null />property>
		
		<property name="properties">
			<props>
				<prop key="driver">com.mysql.jdbc.Driverprop>
				<prop key="url">jdbc:mysql://localhost:3306/mybatisprop>
				<prop key="username">rootprop>
				<prop key="password">rootprop>
			props>
		property>

	bean>

三、基于注解的配置方式

常用定义Bean的注解有四种

  1. @Component用于Spring中的Bean(普通的类)
  2. @Repository 用于对DAO实现类进行标注
  3. @Service 用于对Service实现类进行标注
  4. @Controller 用于对Controller实现类进行标注

它们的功能都表示定义一个bean,只是用名字来划清界限

@Resource和@Autowired都是做bean的注入时使用
共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
超全的SpringIOC和DI实践_第1张图片
不同点
(1)Resource由J2EE提供,需要导入包javax.annotation.Resource,Autowired为Spring提供的注解。
(2)@Resource默认按照ByName自动注入 。
@Resource有两个重要的属性:name和type。如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
@Autowired默认是按照类型byType装配依赖对象。
@Autowired默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。

@Service
public class TestServiceImpl {

	public void print(){
		System.out.println("我是TestServiceImpl的print()");
	}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:config/spring-*.xml"})
public class TestAnnotation {

	@Resource
	private TestServiceImpl my;
	
	@Test
	public void test(){
		my.print();
	}
}

运行结果为:
在这里插入图片描述

需要注意的是,不能直接用@Test做单元测试,否则会出现空指针异常,大致原因如下:
junit单元测试是一个独立的单元测试,它跟你的上下文没有关系,原因据说是因为spring为了考虑安全性问题,在多线程情况下,不支持直接使用 @Resouce 注解方式进行直接的bean注入,也就是说,如果在多线程调用该注入实例化的变量时,将会报NullPointerException 。
解决方案是在需要测试的类上面添加Spring提供的单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:config/spring-*.xml"})

除了需要导入单元测试的那两个包之外,还需要导入,如果不会单元测试请参考Java之JUnit4单元测试
在这里插入图片描述
细心的同学会发现,@Resource默认按照ByName的方式进行自动装配,那么为什么上面的测试代码把名字命名为my也可以运行成功,探究@Resource的原理就知道了。
既不指定name属性,也不指定type属性,则自动按byName方式进行查找。如果没有找到符合的bean,则回退为一个原始类型进行进行查找,如果找到就注入。也就是说,如果按byName找不到,则按byType去找。

四、获取IOC容器的方式

获取IOC容器,其实就是获取Spring的上下文的容器,即ApplicationContext对象,通过该对象可以得到容器中定义的Bean。

方法一: 直接加载配置IOC上下文的XML文件

ApplicationContext context=new ClassPathXmlApplicationContext("config/spring-context.xml");

方法二: 通过Spring提供的工具类获取容器对象

		ServletContext application=request.getServletContext();
		ApplicationContext context1 = WebApplicationContextUtils.getRequiredWebApplicationContext(application);
		ApplicationContext context2 = WebApplicationContextUtils.getWebApplicationContext(application);

这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。
上面两个工具方式的区别是,前者在获取失败时抛出异常,后者返回null。
由于spring是注入的对象放在ServletContext中的,所以可以直接在ServletContext取出 WebApplicationContext 对象:

WebApplicationContext context = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

方法三: 继承自抽象类ApplicationObjectSupport
抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。 Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。
方法四: 继承自抽象类WebApplicationObjectSupport
类似上面方法,调用getWebApplicationContext()获取WebApplicationContext
方法五: 实现接口ApplicationContextAware
实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。 Spring初始化时,会通过该方法将ApplicationContext对象注入。

获取ioc容器之后,就可以根据需要得到容器里面的bean对象了,可以通过ApplicationContext对象的getBean方法得到

		Address address=(Address) context.getBean("address");
		User user=(User) context.getBean(User.class);

第一种方式是通过bean的ID得到的,第二种方式是通过bean的类型得到的,如果得到的结果不是唯一,则会发生异常。

参考链接
https://blog.csdn.net/m_q_x/article/details/77881529
https://blog.csdn.net/Changui_/article/details/78208315
https://blog.csdn.net/khandudu/article/details/81206400

你可能感兴趣的:(spring,SSM)