zoukankan      html  css  js  c++  java
  • Spring文档阅读之IOC

    IOC Inversion Of Controller

    IOC
    控制反转可以理解为类只定义依赖的对象,容器在创建类的实例时通过依赖对象的构造方法注入依赖的对象(或者在Spring中称为bean).
    IOC容器的基础包是org.springframework.beans and org.springframework.context,BeanFactory是Spring Bean容器的入口,ApplicationContext是BeanFactory的子类,是Spring框架提供的引用配置中心接口,在应用运行期间只读,可以配置为热插拔。
    简而言之,BeanFactory提供配置框架和基本功能,ApplicationContext提供了应用上下文和更多特异性功能。
    ApplicationContext提供:
    BeanFactory访问应用组件的方法,继承自ListableBeanFactory。
    使用一般方法加载文件资源的能力,继承自ResourceLoader接口。
    发布时间到注册的监听器的能力,继承自ApplicationEventPublisher接口。
    处理消息和支持国际化的能力,继承自MessageSource接口。
    继承自上一级context。定义一个子类context永远会具有优先级。这意味着,一个父类context可以被整个web应用使用,每个servlet都有独立于其他servlet的context。
    org.springframework.context.ApplicationContext接口通过读取配置文件(XML,Java注解,Java代码),示例化,配置和组合对象。
    IOC使应用的类和配置文件结合,在ApplicationContext创建后,就能使用IOC创建的配置好并且可运行的应用。

    IOC配置文件中,通常定义服务层对象,数据访问对象(DAO),显示层对象(Struts Action instance),底层对象(Hibernate SessionFactories, JMS Queues等)。

    Bean
    IOC容器管理一个或者多个Bean,通过用户配置的xml配置文件(比如application.xml),IOC通过创建对应的BeanDefinition(包含Bean的实际类,Bean的作用范围和生命周期,引用的其他Bean或者Bean使用的连接池的大小)
    Bean可以定义一个唯一的id和多个名称(别名),不同的子系统还可以为同一个Bean定义不同的别名并使用。
    Bean定义时,需要指定Class参数(即具体的Bean类,IOC实质创建的是一个包含对应类的BeanDefinition实例)。Bean可以使用类定义的构造方法或者通过对应的工厂化类(工厂方法)创建Bean实例。

    DI
    Dependency Injection 依赖注入
    构造方法注入,IOC通过类的构造方法注入依赖。
    依赖注入过程:
    1.根据用户提供的配置文件,Java配置代码或者注解代码,IOC创建并初始化ApplicationContext。
    2.当创建每一个Bean时,根据Bean需要的构造参数,静态构造方法或者配置文件,提供其依赖的其他Bean。

    如果Bean的scope不是单实例或者默认,那么它只有在被使用的时候才会被创建而不是随IOC容器一起创建。

    循环依赖问题:
    如果BeanA和BeanB通过构造方法互相依赖,那么IOC容器初始化BeanA和BeanB的时候,会抛出BeanCurrentlyInCreationException。
    一个解决方法是不使用构造方法,而是使用setter方法注入依赖(官方不推荐这种做法)。

    自动装配
    IOC可以自动装配具有依赖关系的Bean。

    当两个类具有不同的生命周期时,可以使依赖类继承并实现ApplicationContextAware接口,这样依赖类可以获取Spring容器的应用上下文ApplicationContext进而获取所需要的Bean实例。

    Bean生命周期

    Singleton Scope
    每个Spring IOC容器只会创建一个对应的Bean,每个引用或者访问对应的Bean实例的请求返回的都是同一个Bean实例(This single instance is stored in a cache of such singleton beans, and all subsequent requests and references for that named bean return the cached object. )。

    Prototype Scope
    Spring IOC容器会为每一个请求或者引用创建一个Bean的实例,Prototype Scope适用于有状态的Bean,单例生命周期适用于无状态的Bean。

    定制Bean特性
    Lifecycle Callbacks
    可以在Spring IOC管理Bean的不同生命周期时和IOC容器进行互动,比如实现InitializingBean和DisposableBean接口,就可以实现afterPropertiesSet()和destroy()方法在Bean初始化和销毁后进行自定义的操作。Spring官方推荐在方法上添加 @PostConstruct和@PreDestroy注解来代替实现InitializingBean和DisposableBean,对代码的侵入性更小。

    ApplicationContextAware
    可以获取容器的ApplicationContext,Spring存在一系列的aware接口,就是让aware获取对应的对象,可以看成是一种反馈机制。

    基于注解(annotation-based)的IOC配置

    @Autowried注解
    可以自动注入实现了同一接口的对象,这些对象可以使用@Priority或者@Order对象来定义在集合中的顺序,如
    public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;
    
    // ...
    

    }
    @Primary注解
    当存在多个可选择的依赖Bean时,可以使用该定义使当前Bean成为优先被注入的Bean。

    @Qualifiers注解
    当存在多个可选择的依赖Bean时,可以使用该注解直接定义被注入的Bean的名称(依赖类和被依赖类都要定义同一名称)。

    @Resource注解
    Spring对于JSR-250 @Resource注解的支持,可以使用该注解定义注入的Bean名称来实现依赖注入。
    可以使用@Resource注解来注入当前的ApplicationContext获取应用上下文。

    @PostConstruct和@PreDestroy注解
    在Bean初始化和Bean销毁前被容器自动调用,可以是用户切入Bean的生命周期。

    @Component,@Repository, @Service和@Controller
    @Component注解更为通用,@Repository, @Service和@Controller分别适用于持久层和服务表现层,Spring官方推荐使用@Repository, @Service和@Controller使程序更容易理解并且更好的支持AOP功能。

    很多Spring的注解都可以使用来生成新的组合功能注解,比如@RestController就是@Controller和@ResponseBody的组合。

    一般来说,需要在应用的@Configuration类添加@ComponentScan(basePackages = "org.example")注解使其可以自动扫描并注入实现了被依赖接口的类。

    @Bean注解
    基本可以认为和@Component注解有一样的效果,和@Configuration一起使用(个人认为不如使用@Component系列注解,更加便于理解并且更好的支持AOP)。
    @Configuration
    public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
    

    }

    基于注解的Spring IOC容器创建的是AnnotationConfigApplicationContext,可以通过@Configuration注解的类初始化Spring容器:
    public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
    }

    如下代码实现了和@ComponentScan(basePackages = "com.acme") 代码相同的功能,扫描com.acme包并且将所有@Component系列注解注释的类初始化到容器中:
    public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");
    ctx.refresh();
    MyService myService = ctx.getBean(MyService.class);
    }

    @Bean注解可以参与容器操作Bean的各个生命周期,最典型的是init和destory:
    public class BeanOne {

    public void init() {
        // initialization logic
    }
    

    }

    public class BeanTwo {

    public void cleanup() {
        // destruction logic
    }
    

    }

    @Configuration
    public class AppConfig {

    @Bean(initMethod = "init")
    public BeanOne beanOne() {
        return new BeanOne();
    }
    
    @Bean(destroyMethod = "cleanup")
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
    

    }
    @Configuration注解标识的类表示其是一个Bean定义资源

  • 相关阅读:
    如何锻炼出最牛程序员的编码套路
    如果仔细观察他们,你会发现他们时时都在锻炼
    单纯地每天埋头于工作并不能算是真正意义上的锻炼
    把全世界的人们都联系在一起,提升人们的社交参与度
    HTML5十五大新特性
    html5的八大特性
    【贪心】【二维偏序】【权值分块】bzoj1691 [Usaco2007 Dec]挑剔的美食家
    【分块】【链表】bzoj2738 矩阵乘法
    【分块】bzoj3343 教主的魔法
    【线段树】bzoj3747 [POI2015]Kinoman
  • 原文地址:https://www.cnblogs.com/Simon-cat/p/10005205.html
Copyright © 2011-2022 走看看