Spring IOC

1.1spring概述及IOC概念

  1. spring特点

    1. 开源的免费的框架

    2. 轻量级的、非侵入式的框架

    3. 提供了控制反转、面向切面编程的功能

    4. 支持事务处理、支持大多数框架的整合

    5. 配置十分繁琐

  2. spring七大模块

    1. 图例

       

       

    2. 详解

      1. 核心容器(Spring Core):核心容器提供Spring框架的基本功能即依赖注入

      2. 应用上下文(Spring Context):一个配置文件,用于向Spring框架提供上下文信息,包括国际化、邮件处理等企业级功能

      3. 面向切面编程(Spring AOP):提供面向切面编程的功能

      4. JDBC和DAO模块(Spring DAO):提供了模块化编写DAO层代码的功能

      5. 对象实体映射(Spring ORM):提供了整合ORM框架实现对象实体相互映射的功能

      6. Web模块(Spring Web):提供了基于应用上下文的web上下文

      7. MVC模块(Spring Web MVC):提供了基于Spring实现的MVC框架

  3. IOC相关概念

    1. 控制反转(IOC),主动创建依赖对象的控制权被反转了,依赖对象不再主动创建,从而降低程序耦合度,增强代码复用性

    2. 依赖注入(DI),控制反转的一种实现方式,控制权被交于IOC容器,依赖的对象将会被IOC容器以注入的方式添加到需要的地方,一般spring可以通过属性、构造方法或工厂方法的参数来确定依赖

      1. set注入:通过set方法的参数来确定依赖,基于set方法,优点是按需注入,可以解决循环依赖问题,但对应属性不能以final修饰,例子如下

        @Component
        public class FirstBean {
           private SecondBean sb;
           public SecondBean getSb() {
               return sb;
          }
           @Autowired
           public void setSb(SecondBean sb) {
               this.sb = sb;
          }
        }
      2. 构造器注入:通过构造方法的参数确定依赖,基于构造方法,优点是减少了对spring的依赖,确保了注入的对象不为空且完成了初始化,同时对于属性会被加上final修饰,并且出现循环依赖时还会抛异常,但构造器的参数可能过长,例子如下

        @Component
        public class FirstBean {
           private SecondBean sb;
           @Autowired
           public FirstBean(SecondBean sb) {
               this.sb = sb;
          }

           public SecondBean getSb() {
               return sb;
          }
           public void setSb(SecondBean sb) {
               this.sb = sb;
          }
        }
      3. field注入(不推荐):通过属性来确定依赖,基于反射,优点是简洁明了,缺点是对spring依赖过高,无法解决循环依赖也不会抛异常,并且对应属性也不能用final修饰,例子如下

        @Component
        public class FirstBean {
           @Autowired
           private SecondBean sb;

           public SecondBean getSb() {
               return sb;
          }
           
           public void setSb(SecondBean sb) {
               this.sb = sb;
          }
        }
    3. IOC容器,用于管理bean并提供依赖注入的功能,容器会通过读取configuration元数据获取有关objects实例化、配置和汇编的指令,spring中主要提供了具备完整依赖注入功能的BeanFactory与BeanFactory的超集ApplicationContext这两种容器,相较而言,ApplicationContext还会提供一些类似于国际化等的企业级功能,并且其单例bean默认非懒加载

      1. Configuration元数据:是对objects创建、管理的一些描述,如该object是否为bean、是singleton还prototype、其属性是否需要注入,应该注入何种对象等,元数据可以为XML、Java注解、Java代码

        1. XML,不安全、查找类不方便、可读性差、配置不简洁、修改配置不用重编译、非侵入、自由度低、可注入非自己创建的类

        2. Java注解,安全、方便、可读性很好、配置十分简洁、修改配置要重编译、侵入、自由度高、不可注入非自己创建的类

        3. Java配置,安全、不方便、可读性一般、配置比较简洁、修改配置要重编译、非侵入、自由度非常高、可以注入非自己创建的类

      2. 使用实例

        //bean类
        @Component
        @Data
        public class FirstBean {
           private String name;
        }

        //Configuration类
        @Configuration
        @ComponentScan("org.example.bean")
        public class SpringConfiguration {
        }

        //启动类
        public class MyTest {
           public static void main(String[] args) {
               ApplicationContext ac=new AnnotationConfigApplicationContext(SpringConfiguration.class);
               FirstBean fb=ac.getBean(FirstBean.class);
               System.out.println(fb.toString());
          }
        }
    4. bean,是对象,IOC容器基于我们提供给它的configuration来实例化、组装和管理这些对象,常见的元数据及对应信息如下

      1. beanDefinition:一个用于存储bean相关信息的对象,如bean的类名、scope、属性、构造函数的,Spring容器启动时会通过beanDefinitionReader去获取各个bean相关属性和配置信息并将它们存放在对应的beanDefinition中,然后将这些beanDefinition存放在map中,之后根据beanDefinition中的类名、构造函数、构造函数参数,使用反射就可以创建对应的bean了,非懒加载的bean会在此时直接创建并存放在另一个map便于之后直接获取使用

      2. FactoryBean:工程bean,也由Spring容器管理,可以生产和修饰一些bean,若对AOP中对应类加以修饰形成所需的bean

      3. bean生命周期图

         

         

    5. Spring循环依赖解决方式

      1. 前提:

        1. Spring实例化bean会分三步,分别为调用构造方法实例化,通过set方法填充属性,通过init方法对bean初始化

        2. bean存放于三级缓存中,一级缓存,用于存放完全初始化好的bean,二级缓存尚未填充属性的bean,三级存放正在实例化的bean,Spring会从一级到三级去尝试获取到对应bean

      2. 循环依赖解决过程如下

        1. A创建过程中需要 B,于是A将自己放到三级缓里面,去实例化B

        2. B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了,则将其作为自己的注入属性

          1. 然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A

          2. B 顺利初始化完毕,将自己放到一级缓存里面,此时B里面的A依然是创建中状态

        3. 然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面

    6. 自动装配常见值及解释

      1. no,默认值,即不进行自动装配,需要通过注解如@Autowire来主动指明该属性、方法需要主动装配

      2. byName,按照beanName进行自动装配,使用setter注入

      3. byType,按照beanClass进行自动装配,使用setter注入

      4. constructor,类似于byType,不过通过构造器注入

1.2IOC中常用注解

  1. 声明bean的相关注解

    1. 作用于类上的注解

      1. @Component,通用注解,当不知道这个类属于哪一层的时候可以通过该注解来标明为bean,这些bean的默认名称为第一个字母小写的类名,类型就是注解作用类的类型

      2. @Controller,组合了@Component的注解,用于声明控制层的类为bean

      3. @RestController,组合了@Controller和@ResponseBody的注解,同样用于声明控制层的类为bean,并指明该类返回的是数据而非视图,数据默认是json格式

      4. @Service,组合了@Component的注解,用于声明服务层的类为bean

      5. @Repository,组合里@Component的注解,用于声明数据访问层的类为bean

    2. 作用域方法上的注解

      1. @Bean,用于指明对应方法的返回值为一个bean,需要配合@Configuration使用,该bean的名称默认为方法的名称,类型为方法的返回类型,其详尽信息如下

        @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public @interface Bean {
           @AliasFor("name")
           String[] value() default {}; //用于指明别名

           @AliasFor("value")
           String[] name() default {};

           /** @deprecated */
           @Deprecated
           Autowire autowire() default Autowire.NO; //默认不启用自动装配

           boolean autowireCandidate() default true; //默认开启自动条件匹配

           String initMethod() default ""; //用于指明初始化方法

           String destroyMethod() default "(inferred)"; //用于指明消除方法
        }
  2. 修饰bean的相关注解

    1. @Scope,用于指明bean的作用域,常见作用域如下

      1. singleton,默认值,单例,全局有且仅有一个实例

      2. prototype,原型,每次获取Bean的时候都会创建一个新的实例

      3. request,针对每一次http请求都会产生一个新的bean,同时该bean只在此次http请求内有效

      4. session,针对每一次无bean的http请求都会产生一个新的bean,同时该bean只在此个session中有效

      事实上90%以上的业务使用singleton即可,这也就是为什么Spring用singleton作为默认值,不过由于singleton保证了全局只有一个实例,使得如果实例中有非静态变量时,会因共享资源的竞争而导致线程安全问题,当然因为是单例所以不用频繁GC,同时也会节省内存,使得总体性能会有所提升,@Scope实现如下

      @Target({ElementType.TYPE, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Scope {
         @AliasFor("scopeName")
         String value() default "";

         @AliasFor("value")
         String scopeName() default "";

         ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
      }
    2. @Primary,指明该bean为首选bean,当有多个符合要求的bean时会首先选择该个bean

    3. @Qualify,可在注解中写入名称来详细指明注入的bean,如@Qualify("firstBean")就是指明注入一个名称为firstBean的bean

    4. @Profile,组合了@Condition的注解,指明bean的方法或bean在什么情况下起作用,如@Profile("test")需要在spring.profiles.active = test时才有效,对于Springboot可以直接在application.profiles中设置,也可以通过容器的getEnvironment().setActiveProfiles("test")方法设置

  3. 配置类的相关注解

    1. @Configuration,指明该类为bean并将其设置为配置类,配置类中可以有多个返回bean的方法,这些方法需要用@Bean注释

    2. @Import,用于导入其他多个配置类到一个配置类中,如@Import({Config.clsss,BasicConfig.clss})就是将Config和BasicConfig两个配置类导入到当前配置类中

    3. @PropertyResource,用于导入相应的资源文件,可以配合@Value来获取对应的资源信息,其属性为文件的路径,需要加上classpath:来指明是类路径,如@PropertyResource("classpath:test.properties"),在maven项目中就是导入resources目录下的test.properties文件

    4. @ComponentScan,用于指明扫描的范围,地址是以类路径起始的,如@ComponentScan("basic")就是在maven项目中扫描Java包下的basic包中的所有文件,默认扫描该类所在包及其子包中的所有类

  4. 注入bean和属性的相关注解

    1. @Autowired,用于装配bean,默认按类型装配,详情如下

      @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Autowired {
         boolean required() default true; //是否必要,即是否允许为null,默认不允许
      }
    2. @Resource,JDK1.6支持的注解,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名为名称来按照名称查找,如果注解写在setter方法上默认取属性名作为名称来查找装配,当找不到与名称匹配的bean时才按照类型进行装配,不过只要指定了name属性则只会按照名称进行装配

    3. @Value,用于注入资源信息,如MySQL相关配置等,在使用前需要通过@Properties先导入对应的资源文件,使用格式为@Value("${properties文件中对应key值}"),通过它注入属性不需要set方法

posted @ 2020-07-30 10:21  vignetting  阅读(10)  评论(0)    收藏  举报