一、前言引入

Spring的依赖注入的最大亮点就是你所有的 Bean 对 Spring 容器的存在是没有意识的。即你可以将你的容器替换成别的容器。

但是在实际的项目中,我们不可避免的要用到 Spring 容器本身的功能资源(发生耦合),这时候 Bean必须要意识到 Spring 容器的存在,才能调用 Spring 所提供的资源,这就是所谓的Spring Aware。其实Spring Aware本来就是 Spring 设计用来框架内部使用的,若使用了 Spring Aware,你的Bean将会和 Spring 框架耦合(引用)。

一、Bean装配之Aware接口
二、Bean装配之自动装配
三、Bean装配之Resource

二、具体内容

2.1 Bean装配之Aware接口

aware,翻译过来是知道的,已感知的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware前面的含义。
实现BeanNameAware接口,可以让该Bean感知到自身的BeanName(对应Spring容器的BeanId属性)属性,同理,其他的Aware接口也是为了能够感知到自身的一些属性。
比如实现了ApplicationContextAware接口的类,能够获取到ApplicationContext,实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。

  • Spring中提供了一些以Aware结尾的接口,实现了Aware接口的bean在初始化之后,可以获取相应的资源
  • 通过Aware接口,可以对Spring相应资源进行操作(慎重)
  • 为对Spring进行简单的扩展提供了方便的入口

Name

Injected Dependency

ApplicationContextAware

Declaring ApplicationContext

ApplicationEventPublisherAware

Event publisher of the enclosing ApplicationContext

BeanClassLoaderAware

Class loader used to load the bean classes

BeanFactoryAware

Declaring BeanFactory

BeanNameAware

Name of the declaring bean

BootstrapContextAware

Resource adapter BootstrapContext the container runs in. Typically available only in JCA aware ApplicationContexts

LoadTimeWeaverAware

Defined weaver for processing class definition at load time

示例代码:定义类MoocApplicationContext 实现 ApplicationContextAware 接口

package com.imooc.aware;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/*
 * 实现接口 ApplicationContextAware
 */
public class MoocApplicationContext implements ApplicationContextAware {

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		// 加载的了这个Bean的IOC容器上下文信息
		System.out.println("MoocApplicationContext:" + applicationContext.getBean("moocApplicationContext"));
	}

}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd ">
    
    <bean id="moocApplicationContext" class="com.imooc.aware.MoocApplicationContext"></bean>
</beans>

测试方法

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

public class TestAware {

	private static ApplicationContext context;
	@Test
	public void testMoocApplicationContext(){
	
		context = new ClassPathXmlApplicationContext(
			 "spring-aware.xml"); 
		
	}
}

spring项目接口写法 spring 接口_自动装配


示例代码:定义类 MoocBeanName 实现 BeanNameAware接口

package com.imooc.aware;

import org.springframework.beans.factory.BeanNameAware;

public class MoocBeanName implements BeanNameAware{

	@Override
	public void setBeanName(String name) {
		System.out.println("MoocBeanName:" + name);
	}
}

spring项目接口写法 spring 接口_Aware接口_02


同时实现两个接口

/* 
 * 在 此接口里面 得到Bean 的 name,并把beanName  赋值给成员变量, 在另外一个Bean里面 通过
 * getBean()方法 得到 由setBeanName()方法 传入 的实例
 */
public class MoocBeanName implements BeanNameAware,ApplicationContextAware{

	private String beanName;
	@Override
	public void setBeanName(String name) {
		this.beanName = name;
		System.out.println("MoocBeanName:" + name);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("setApplicationContext:" + applicationContext.getBean(this.beanName).hashCode());
	}
}

测试

public class TestAware {

	private static ApplicationContext context;

	@Test
	public void testMoocBeanName() {

		context = new ClassPathXmlApplicationContext("spring-aware.xml");
		System.out.println("testMoocBeanName:" + context.getBean("moocBeanName").hashCode());
	}

spring项目接口写法 spring 接口_Resource接口_03


以上的代码我们验证了什么? 实际上证明了 无论是 通过Aware接口 实现IOC容器的上下文的应用,还是 在启动的时候 直接使用getBean方法获取 实例 ,所获取的是同一个实例,两种方式取得实例的hashCode值是一样的。

  • 深度解析:BeanNameAware接口帮助Java Bean知道(意识到)自己在配置文件中的 id,实现BeanNameAware接口,实现方法为setBeanName()方法,初始化该对象后Spring会执行回调方法,将 id 设置进来。SetBeanName方法的回调发生在所有参数被设置完之后,初始化(init-method)被执行之前。

2.2 Bean装配之自动装配

Bean的自动装配类型

释义

NO

不做任何动作

Byname

根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配;

ByType

如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该属性类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配,如果没有找到相匹配的bean,则什么事都不发生

Constructor

与byType方式类似,不同之处在于它应用于构造器参数,如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。

代码示例(byName):
配置文件

<?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" 
        default-autowire="byName" >
    
    	<bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService"></bean>
    	<bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO"></bean>
    
    </beans>

定义DAO层

package com.imooc.autowiring;

public class AutoWiringDAO {
	
	public void say(String word) {
		System.out.println("AutoWiringDAO:" + word);
	}
}

定义Service层

package com.imooc.autowiring;
    
    public class AutoWiringService {
    
    	public AutoWiringDAO autoWiringDAO;
    	// 成员变量的set方法
    	public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
    		System.out.println("setAutoWiringDAO");  // 验证是否调用了 set 方法
    		this.autoWiringDAO = autoWiringDAO;
    	}
    	// 定义 service 层的  say 方法
    	public void say(String word) {
    		this.autoWiringDAO.say(word);
    	}
    }

测试:

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

import com.imooc.autowiring.AutoWiringService;
/*
 * 整个调用过程,调用service层的实例,调用service的say方法,,再调用autoWiringDAO 实例的say()方法
 */
public class TestAutoWiring {
	private static ApplicationContext context;

	@Test
	public void testSay() {

		context = new ClassPathXmlApplicationContext("spring-autoWiring.xml");
        AutoWiringService service = (AutoWiringService) context.getBean("autoWiringService");
        service.say("this is a test.");
	}
}

运行结果:

spring项目接口写法 spring 接口_Resource接口_04

在配置文件中设置了 defaultautowire=“byName” ,在配置文件中不需要 再写 property
属性配置,整个配置看起来简洁一些。但是:依赖不能明确管理,可能会有多个bean同时符合注入规则。没有清晰的依赖关系。

代码示例(byType)自动装配
配置文件

<?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" 
        default-autowire="byType" >
    
    	<bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService"></bean>
    	<bean id="autoWiringDAO222" class="com.imooc.autowiring.AutoWiringDAO"></bean>
    
    </beans>

我们试试byName 可不可以? 抛了异常

spring项目接口写法 spring 接口_Resource接口_05

构造器default-autowire="constructor"

public class AutoWiringService {

	public AutoWiringDAO autoWiringDAO;
	
	// 构造器
	public AutoWiringService(AutoWiringDAO autoWiringDAO) {
		System.out.println("AutoWiringService"); // 验证是否调用 
		this.autoWiringDAO = autoWiringDAO;
	}
	
	// 成员变量的set方法
	public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO) {
		System.out.println("setAutoWiringDAO");
		this.autoWiringDAO = autoWiringDAO;
	}
	
	// 定义 service 层的  say 方法
	public void say(String word) {
		this.autoWiringDAO.say(word);
	}
}

构造注入是在IOC容器查找构造器方法传入参数的类型,在IOC容器中查看是不是有相应Bean的实例,也就是说 根据类型 的话 就和 id 没有关系,是根据Bean的类型匹配的。

<bean class="com.imooc.autowiring.AutoWiringDAO"></bean>

这样代码也可以正常运行;

spring项目接口写法 spring 接口_spring项目接口写法_06

2.3 Bean自动装配之Resource

JDK 提供的访问资源的类( File 等)不能很好满足各种某些资源的访问需求。比如缺少从类路径和 Web 容器的上下文中获取资源的资源操作类。Spring 的 Resource 接口提供了更好用的资源访问能力。Spring 使用 Resource 访问各种资源文件,配置文件资源,国际化属性资源等。

针对于资源文件的统一接口

Resource

释义

UrlResource

URL对应的资源,根据一个URL地址即可 构建

ClassPathResource

获取类路径下的资源文件

FileSystemResource

获取文件系统里面的资源

ServletContextResource

ServletContext 封装的资源,用于访问ServletContext环境下的资源

InputStreamResource

针对于输入流封装的资源

ByteArrayResource

针对于字节数组封装的资源

ResourceLoader 资源加载的一个类
所有的 Application context 都实现了这个接口,并且它们都可以获取Resource 实例

public interface ResourceLoader {
	Resource getResource(String location);
}
Resource template = ctx.getResource("文件位置");
Resource template = ctx.getResource("classpath:some/myTemplate.txt");
Resource template = ctx.getResource("file:/path/myTemplate.txt");

文件名前缀和使用方式及释义

spring项目接口写法 spring 接口_spring项目接口写法_07


定义Resource类

package com.imooc.resource;

import java.io.IOException;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;

public class MoocResource implements ApplicationContextAware {

	private ApplicationContext applicationContext;
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	
	public void resource() throws IOException {  // 配置文件在本地Resource中
		 Resource resource = applicationContext.getResource("classpath:config.txt");
		 System.out.println("文件名:" + resource.getFilename());
		 System.out.println("文件长度:" + resource.contentLength());
	}
	
}

配置文件

<?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" 
    default-autowire="constructor" >

	<bean id="moocResource" class="com.imooc.resource.MoocResource"></bean>

</beans>

测试类

package com.imooc.test.resource;

import java.io.IOException;

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

import com.imooc.resource.MoocResource;

public class TestResource {
	private static ApplicationContext context;

	@Test
	public void testResource() throws IOException {

		context = new ClassPathXmlApplicationContext("spring-resource.xml");
		MoocResource moocResource = (MoocResource) context.getBean("moocResource");
		moocResource.resource();
	}

}

参考文档:https://www.jianshu.com/p/c5c61c31080b