IOC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建与维护,而是由外部容器负责创建和维护。
到底什么是控制反转,就是获得依赖对象的过程被反转了。控制反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。
DI:依赖注入 ,创建对象并且组装对象之间的关系。就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。
Spring容器并不是只有一个,它自带了许多容器实现,可以归为两种不同的类型。
bean工厂(org.springframework.beans.factory.BeanFactory)
应用上下文ApplicationContext(org.springframework.context.ApplicationContext接口中定义)
ApplicationContext是spring中的容器应用上下文,可以加载配置文件中定义的bean,保存bean对象,全权负责对象的创建与组装。这个容器在org.springframework.context.ApplicationContext接口中定义。ApplicationContext包含BeanFactory所有的功能,所以一般推荐使用ApplicationContext。spring中自带了多种应用上下文的实现,他们的不同之处就在于如何加载配置。
ApplicationContext接口的实现方式:
①AnnotationConfigApplicationContext:从一个或多个基于java配置类中加载应用上下文。
②文件方式:从文件系统下的xml文件中加载已被定义的bean。提供xml文件在磁盘的完整路径
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("F://workspace/appcontext.xml")
③Classpath:从类路径下的xml文件中加载已被定义的bean。提供xml文件的相对路径(应用程序类路径下的xml配置文件)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-context.xml");
④Web应用中依赖servlet或Listen
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
应用上下文准备就绪之后,就可以调用上下文的getBean()方法从Spring容器中获取bean了。
在web项目中,系统一旦启动,web服务器会初始化spring的上下文的。所以以上获得spring上下文环境的方法主要是在测试类中使用,系统不启动的情况下手动初始化spring上下文再获取对象。
装配Bean的三种方式:
第一种是通过XML装配bean,Spring的配置文件applicationContext.xml
<?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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
在配置文件的顶部需要声明多个XML模式(XSD)文件,这些文件定义了配置Spring的XML元素。
1.声明一个简单的bean
在基于XML的Spring配置中声明一个bean,我们要使用Spring-beans模式中的一个元素<bean>。
<bean id="exampleBean" class="example.ExampleBean">
声明了一个简单的bean,创建这个bean的类由class属性来指定,并且要使用全限定的类名。
当Spring发现这个<bean>元素时,会调用类的默认构造器来创建bean。等同于ExampleBean eb = new ExampleBean ();
2.注入bean的引用有两种方式:构造器注入和setter方法注入
Ⅰ构造器注入
<bean id="exampleBean" class="example.ExampleBean">
<constructor-arg ref="***"> //ref是引用其他bean的id
<constructor-arg value="***">//value指的是以字面量的方式注入到构造器之中
</bean>
当spring遇到这个bean时会创建一个ExampleBean的实例,<constructor-arg>元素会告知Spring要将一个id为***的bean引用或者字面量***传递到ExampleBean的构造器之中。
如果类中的属性是列表,注入时使用<list>标签
<constructor-arg>
<list>
<value>***</value>
或者
<ref bean="***">
</list>
</constructor-arg>
作为替代方案,可以使用Spring的c-命名空间,c-命名空间是在Spring3.0中引入的。要使用它的话要在XML的顶部声明其模式,xmlns:c="http://www.springframework.org/schema/c"。具体用法省略。
Ⅱ setter方法注入
<bean id="exampleBean" class="example.ExampleBean">
<property name=" " ref="***"> //ref是引用其他bean的id
<property name="" value="***">//value指的是以字面量的方式注入到属性中
</bean>
<property>元素为属性的setter方法提供功能,这个元素会告知Spring要将一个id为***的bean引用或者字面量***传递到setter方法之中。
作为替代方案,可以使用Spring的p-命名空间,p-命名空间是在Spring3.0中引入的。要使用它的话要在XML的顶部声明其模式,xmlns:p="http://www.springframework.org/schema/p"。具体用法省略。
还可以使用Autowiring(在<beans>里的属性default-autowire="byName" "byType"等等)
No:不做任何操作
byName:根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。
byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多给该类型相同的bean,那么抛出异常。如果 没有找到相匹配的bean,则什么事都不发生。
Constructor:与byType方式相似,不同在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。
Resources:针对于资源文件的统一接口
①UrlResource:URL对应的资源,根据一个URL地址即可构建
②ClassPathResource:获取类路径下的资源文件
③FileSystemResource:获取文件系统里面的资源
ResourceLoader是对resource加载的一个类,所有的application contexts实现了ResourceLoader接口
public interface ResourceLoader{
Resource getResource(String location);
}
前缀:classpath: file: http: none
//实现ApplicationContextAware接口,获得ApplicationContext对象,调用getResource(String location)方法,获得资源对象。
public class helloResource implements ApplicationContextAware{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)throws BeansException{
this.applicationContext=applicationContext;
}
public void resource(){
Resource resource = applicationContext.getResource("classpath:config.txt");
System.out.println(resource.getFilename());
System.out.println(resource.contentLength());
}
}
第二种是自动化装配bean
组件扫描:Spring会自动发现应用上下文中所创建的bean
自动装配:Spring会自动满足bean之间的依赖
一、组件扫描
@component 表明该类会作为组件类,并告知Spring要为这个类创建bean,即注册Bean到ApplicationContext中。
@component 是一个通用注解,可用于任何bean
@Repository @Service @Controller是更具有针对性的注解
@Repository通常用于注解DAO类,即持久层
@Service通常用于注解Service类,即服务层
@Controller通常用于注解Controller类,即控制层
但是组件扫描默认是不启用的。我们还需要显示配置一下Spring,从而命令它去寻找带有@component @Repository @Service @Controller注解的类,并为其创建bean。
@ComponentScan注解启用了组件扫描
@Configuration
@ComponentScan
public class HelloConfig{
}
如果没有其他配置,@ComponentScan默认会扫描与配置类相同的包及其子包。但是如果想扫描不同的包,就需要设置基础包@ComponentScan("***"),括号里指明包的名称。如果你想设置多个基础包,可以通过basePackages属性进行配置,要扫描的包为一个数组
@ComponentScan(basePackages={"***","***"}) 这种所设置的基础包是以String类型表示的。类型不安全
还可以@ComponentScan(basePackageClasses={***.class,***.class}) 指定为包中所包含的类或接口。
还可以使用XML的配置方式启用组件扫描,使用Spring Context命名空间的<context:component-scan>元素。
<context:component-scan base-package="包名"></context:component-scan>
为组件扫描的bean命名
Bean的名称是由BeanNameGenerator生成的。默认是将类名的第一个字母小写。如果想指定这个Bean的ID,那么@component("***"),括号里为bean的id属性值。
二、自动装配
@Autowired注解,可以用于成员变量,setter方法和构造器上。满足bean的依赖。
如果找不到匹配的bean,将会抛出异常,可以通过@Autowired(required=false)来避免。这种情况下,如果没有匹配的bean,Spring就会让这个bean处于未装配的状态。如果在代码中没有进行null检查,这个处于未装配状态的bean就可能会出现NullPointerException。
@Autowired是由Spring BeanPostProcessor处理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载
处理自动装配的歧义性
如果有多个bean满足装配,会产生歧义性。
标示首选bean,可以使用@Primary和@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。
限定自动装配的bean,可以使用@Qualifier注解缩小范围,@Qualifier("***")所设置的参数就是想要注入的bean的ID。这种情况下如果对类名称进行修改,就会导致限定符失效。
所以我们可以创建自定义的限定符,为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。在这里需要做的就是在bean声明上添加@Qualifier("***")注解,
第三种是通过Java代码装配bean
有时候如果你想将第三方库中的组件装配到应用中,是没办法在类上添加@Component和@Autowired注解的,因此不能使用自动化装配方案。在这种情况下就需要用显示装配方式了,有两种,一种是基于XML的,一种是基于Java的。
创建配置类,在类上添加@Configuration注解,表明这个类是一个配置类。
在java配置类中声明一个bean,需要用到@Bean注解,编写一个方法,该方法返回创建所需类型的实例,在该方法上添加@Bean注解。默认情况下,bean的ID与带有@Bean注解的方法名一样,如果想指定bean的ID,@Bean(name="***")。
@Configuration
public class AppConfig{
@Bean
public MyService myService(){
return new MyServiceImpl();
}
}
@ImportResource(classpath:/com/properties.xml")引入资源文件
public class AppConfig{
@Value("${jdbc.url}")从资源文件中加载资源配置
private String url;
@Value("${jdbc.username}")从资源文件中加载资源配置
private String username;
@Value("${jdbc.password}")从资源文件中加载资源配置
private String password;
@Bean
public DataSource dataSource(){
return new DriverManagerDataSource(url,username,password);
}}<bean>的作用域
在默认情况下,Spring应用上下文中所有bean都是作为以单例的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次注入的都是同一个实例。如果想改变作用域,可以使用@Scope("***")注解或者<bean id="" class="" scope="">
singleton:单例,在整个应用中,只创建bean的一个实例
prototype:原型,每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
request:请求,在web应用中,为每个请求都创建一个bean实例,且仅在当前request内有效。
session:会话,在web应用中,为每个会话都创建一个bean实例,当前session内有效。
Bean的生命周期(定义 初始化 使用 销毁)
初始化:实现org.springframework.beans.factory.InitializingBean接口,覆盖afterPorpertiesSet方法
或者在<bean>标签中配置init-method
销毁:实现org.springframework.beans.factory.DisposableBean接口,覆盖destroy方法。
或者在<bean>标签中配置destroy-method
如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法
如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来。