Spring的IOC总结

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所在的应用上下文的引用传入进来。






猜你喜欢

转载自blog.csdn.net/yy23yy80/article/details/80763004