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对象。
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"));
}
}
配置文件
测试方法
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");
}
}
示例代码:定义类 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);
}
}
/*
* 在 此接口里面 得到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());
}
以上的代码我们验证了什么? 实际上证明了 无论是 通过Aware接口 实现IOC容器的上下文的应用,还是 在启动的时候 直接使用getBean方法获取 实例 ,所获取的是同一个实例,两种方式取得实例的hashCode值是一样的。
2.2 Bean装配之自动装配
Bean的自动装配类型 | 释义 |
---|---|
NO | 不做任何动作 |
Byname | 根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配; |
ByType | 如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该属性类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配,如果没有找到相匹配的bean,则什么事都不发生 |
Constructor | 与byType方式类似,不同之处在于它应用于构造器参数,如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。 |
代码示例(byName):
配置文件
定义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.");
}
}
在配置文件中设置了 defaultautowire=“byName” ,在配置文件中不需要 再写 property
属性配置,整个配置看起来简洁一些。但是:依赖不能明确管理,可能会有多个bean同时符合注入规则。没有清晰的依赖关系。
代码示例(byType)自动装配
配置文件
我们试试byName 可不可以? 抛了异常
构造器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的类型匹配的。
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");
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());
}
}
配置文件
测试类
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
https://www.cnblogs.com/drafire/p/9273940.html