Spring基础-IOC.md

Spring体系结构

  1. SpringCore

    框架最基础的部分,提供IOC和依赖注入特性

  2. SpringContext

    Spring上下文容器,它是BeanFactory功能加强的一个子接口

  3. SpringWeb

    提供Web应用开发的支持

  4. SpringMVC

    针对Web应用中MVC思想的实现

  5. SpringDao

    对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性

  6. SpringORM

    用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + MyBatis、Spring + JDO的整合等等。

  7. SpringAop

    面向切面编程,它提供了与AOP联盟兼容的编程实现

核心类

  • ApplicationContext 这是spring容器的上下文对象,所有注入的bean都会在容器中,初始化上下文后,就可以通过上下文对象获取容器中的类。

  • BeanFactory

    BeanFactory是接口,提供了OC容器最基本的形式,给具体的IOC容器的实现提供了规范。

    BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。

    ApplicationContext接口,它由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,通常建议比BeanFactory优先

  • FactoryBean

    为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式(如果想了解装饰模式参考:修饰者模式(装饰者模式,Decoration) 我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类.

  • BeanPostProcessor

给容器中注册组件的方式

  1. @Bean 主要用于导入第三方jar或者类
  2. 包扫描+组件的标注注解(@Component @Controller @Service @Repository),主要用于注册自己当前项目中的bean
  3. @Import 快速给容器导入一个组件,相对于@Bean,更灵活.
  4. 使用Spring提供的FactoryBean注入

常用注解

  • @Configuration

    表明这个类是配置类,可以用annotationConfigApplicationContext加载配置类,初始化配置类的配置。

  • @ComponentScan

    自动扫描包下的相关注解 可以自定义扫描规则

  • @ComponentScans ComponentScan的集合配置

  • @Scope 配置容器中的实例生成方式
    有几个可选项:

    • prototype 每次创建一个实例
    • singleton 全局只有一个实例
    • request 每个请求创建一个实例
    • session 每个session会话内共享一个实例

    默认是单实例,创建ioc容器的时候,实例bean就被创建了

    多实例: 仅当在使用的时候才新建实例

  • @Lazy 单实例bean默认在容器启动的时候创建对象,如果配置了lazy注解,则会是在使用时候才会创建并初始化,不在容器启动的时候创建对象。

  • @Conditional

    可以根据条件注册bean到容器中,不满足条件就不注入,满足才注入。例如:实现一个只在windows环境才注入的bean

    //1.先自定义一个条件类,用于条件匹配,该类实现Conditon接口
    public class LinuxCondition implements Condition {
        /**
        * 只在Linux下才注入的匹配规则
        * @param context
        * @param metadata
        * @return
        */
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            //获取beanFactory
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
            Environment environment = context.getEnvironment();
            //获取当前java运行的系统环境
            String property = environment.getProperty("os.name");
            if (property.toUpperCase().contains(("linux".toUpperCase()))) {
                return true;
            }
            return false;
        }
    }
    
    
    //2.使用conditonal注解导入自定义的condition实现类
    
    @Configuration
    public class MainConfig3 {
        //张三只在windows下才会被注入
        @Conditional(WinCondition.class)
        @Bean
        public Person zhangsan() {
            return new Person("zhangsan", 11);
        }
    
        //lisi只在windows下才会被注入
        @Conditional(LinuxCondition.class)
        @Bean
        public Person lisi() {
            return new Person("lisi", 12);
        }
    
    
    }
    

    以上代码在windows环境中指挥注入zhangsan,在linux环境指挥注入lisi

  • @Import

    使用方式

    1. 直接将需要注册的类放入import中。容器会自动注册value里的bean,bean的id为全类名

      @Import(value = {Dog.class, Pig.class})

      @Import(value = {Dog.class, Pig.class})
      @Configuration
      public class MainConfig4 {
          
      }
      /如果打印容器中所有bean的id,会发现包含如下结果
      //cn.ihu.org.demo4.Dog
      //cn.ihu.org.demo4.Pig 
      
    2. 自定义类,继承ImportSelector,实现selectImports方法。bean的id为全类名

      @Import(value = {CustomSelector.class})

      public class CustomSelector implements ImportSelector {
          public String[] selectImports(AnnotationMetadata importingClassMetadata) {
              //返回要导入的类的全类名数组
              return new String[] {"cn.ihu.org.demo4.Cat", "cn.ihu.org.demo4.Desk"};
          }
      }
      
      //如果打印容器中所有bean的id,会发现包含如下结果
      //cn.ihu.org.demo4.Cup 
      //cn.ihu.org.demo4.Desk 
      
    3. 自定义类,继承ImportBeanDefinitionRegistrar接口,实现registerBeanDefinitions方法,通过 BeanDefinitionRegistry的实例对象向容器中注入bean。

    @Import(value = {CustomBeanDefinitionRegistrar.class})

        public class CustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
            /**
            * @param importingClassMetadata 注解信息
            * @param registry 注册类,把需要加入到容器中的类,加入到容器
            */
            public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
                System.out.println(importingClassMetadata.getAnnotationTypes());
                //获取容器中是否注册了Cup类的实例。
                boolean b = registry.containsBeanDefinition("cn.ihu.org.demo4.Cup");
                //如果容器中有Cup类注册进来了,那么我就再注册一个Water类进去。
                if (b) {
                    //要注册的bean必须包装成RootBeanDefinition类
                    RootBeanDefinition beanDefinition = new RootBeanDefinition(Water.class);
                    //向容器中注入一个water类
                    registry.registerBeanDefinition("water", beanDefinition);
                }
    
            }
        }
    
    

    注意:以上三种方式可以放在一起使用,如 @Import(value = {Dog.class, Pig.class, CustomSelector.class, CustomBeanDefinitionRegistrar.class})

  • @Service

  • @Component

  • @Controller

  • @Repository

    以上几个都是用于注入Bean到Spring容器

  • @Value、@PropertySource、@PropertySources

    用于对属性赋值,支持基本字符以及SpringEL表达式

        @Value(#{20-2})
        private Integer age; //会注入值 : 18
    

    也可以用于读取properties文件

    //导入配置文件
    @PropertySource("clsspath:/test.properties")
    
    @Value("${redis.port}") //可以读取在test.propertes中定义的redis.portd的值
    
  • @Autowired、 @Qualified 、@Resources(JSR250)、 @Inject(JSR330,需要导入javax.inject)

    1. @Autowired自动按类型注入,如果有多个同类型的bean被注册到Spring容器中,则需要结合@Qualified,指明具体使用哪一个bean。
      @Autowired可以放在方法,属性,以及构造方法上,当一个组件只有构造方法时即使不显示的声明@autowired,也能够直接注入。
      spring官方推荐在构造方法上使用autowired注解。因为当spring初始化一个类,会优先使用构造方法创建类之后才会注入其成员变量。
    @Service
    public class TestService {
        @Autowired
        @Qualifier("testDao2")
        TestDao dao;
    
        public TestDao getDao() {
            return dao;
        }
    
        public void setDao(TestDao dao) {
            this.dao = dao;
        }
        }
    
    
    1. @Primary注解指定注入时的优先级,该bean在注入时会作为首选项
    @Configuration
    @ComponentScan(basePackages = "cn.ihu.org.demo6")
    public class Config6 {
        @Bean
        @Primary//@Primary注解指定注入时的优先级
        public TestDao testDao2() {
            return new TestDao("2");
        }
    }
    
    
    1. @Resouce 是JSR250的注解,也可以实现依赖注入的功能。
      和@Autowire区别是,@Resouce注入的资源必须存在,否则会报错,而@Autowired可以设置required=false,当资源不存在不会报错。
    @Service
    public class TestService {
        @Resource(name = "testDao2")
        TestDao dao;
    
        public TestDao getDao() {
            return dao;
        }
    
        public void setDao(TestDao dao) {
            this.dao = dao;
        }
    }
    
    1. @Inject JSR330中的标准 需要额外引入javax.inject包,支持@Primary优先级,没有@Autowired(required=false)的功能

@Bean

Bean的生命周期

  • 创建 -> 初始化-> 销毁

    1. 我们可以自定义bean的初始化和销毁方法

      //1.定义一个类
      public class Student {
          public void init() {
              System.out.println("执行初始化方法...");
          };
      
          public void destory() {
              System.out.println("执行销毁方法");
          }
      
      }
      //2.使用bean初始化时候可以指定初始化和销毁方法
      @Configuration
      public class Mainconfig5 {
      
          @Bean(initMethod = "init", destroyMethod = "destory")
          public Student student() {
              return new Student();
          }
      }
      
    2. 可以自定义一个类,实现InitializingBean接口,实现afterPropertiesSet方法,在spring容器创建bean,且为属性赋值之后,会调用。

      自定义一个类,实现DisposableBean接口,实现destroy方法,在bean被销毁的时候调用。

      //创建对应的类
      public class Car implements InitializingBean, DisposableBean {
          /**
          * 当spring容器销毁时候,会调用
          * @throws Exception
          */
          public void destroy() throws Exception {
              System.out.println("执行bean销毁方法");
          }
      
          /**
          * Spring容器当中给,当bean创建完成,属性值赋值完成之后,会调用这个方法
          * @throws Exception
          */
          public void afterPropertiesSet() throws Exception {
              System.out.println("执行bean初始化方法");
          }
      
      
          public Car() {
              System.out.println("创建Bean对象...");
          }
      }
      
      //初始化bean
      @Configuration
      public class Mainconfig5 {
      
          @Bean(initMethod = "init", destroyMethod = "destory")
          public Student student() {
              return new Student();
          }
          
          @Bean
          public Car car() {
              return new Car();
          }
      }
      //spring容器初始化Car类完成,会打印
      //执行初始化方法...
      //创建Bean对象...
      //执行bean初始化方法
      
      
    3. 可以使用JDK的JSR250标准,使用@PostConstruct、 @PreDestroy

                  
      public class School {
      
          @PostConstruct
          public void init() {
              System.out.println("初始话School");
          }
      
          @PreDestroy
          public void destroy() {
              System.out.println("销毁school....");
          }
      
          public School() {
              System.out.println("创建school...");
          }
      }
      
      

BeanPostProcessor

可以处理类初始化前后需要做的事情。postProcessBeforeInitialization方法会在bean初始话之前执行,postProcessAfterInitialization会在bean初始化之后执行。

```
//将该processor注入容器后,spring就会在加载bean的时候,在执行bean的初始化方法前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization、

@Component  
public class CustomProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization:" + beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization:" + beanName);
        return bean;
    }
}

```

Spring中的Aware

Aware接口提供了一种可以通过BeanPostProcessor处理自定义逻辑的方式,在spring初始化BeanPostProcessor之后,对每一个类进行初始化的时候会检查是否实现了aware接口,然后通过不同的接口调用aware的实现方法。具体过程如下
我们首先定义一个自定义的aware接口实现类,并实现对应方法

@Component
public class CustomAware implements ApplicationContextAware, EnvironmentAware,EmbeddedValueResolverAware {

    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        System.out.println(resolver.resolveStringValue("{{os.name}}"));
    }

    @Override
    public void setEnvironment(Environment environment) {
        System.out.println(Arrays.toString(environment.getActiveProfiles()));
    }

    public ApplicationContext getContext() {
        return context;
    }

    public void setContext(ApplicationContext context) {
        this.context = context;
    }
}

我们在测试类中可以看到

public class Demo8ConfigTest {
    @Test
    public void testAwareInterface() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo8Config.class);
        CustomAware customAware = context.getBean(CustomAware.class);
        System.out.println(context == customAware.getContext());//查看注入的容器是否和启动的容器相等,结果是true
    }
}

Spring中的源码如下

1.Spring基础-IOC.md_第1张图片

  1. Spring基础-IOC.md_第2张图片
  2. Spring基础-IOC.md_第3张图片

你可能感兴趣的:(Spring)