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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章