/

Spring学习笔记之IOC容器

基本概念

IOC概念

原先在代码中通过硬编码的方式来进行类的实例化,以及定义各个对象之间的依赖关系。现在将类的实例化操作以及对象之间的依赖关系交给Spring容器来管理。实际上控制器交给容器管理了,所以称之为IOC。Spring通过配置文件或者注解的方式来实现类的实例化,绑定关系等等。

控制bean的创建顺序

depend-on(xml) 或者 @DependsOn(annotation)

控制bean的懒加载

lazy-init=”true”(xml) 或者 @Lazy(annotation)

bean的scope类型

  • singleton 单例,整个容器中只会创建一个对象实例

  • prototype 原型,每次获取bean时都会创建一个新的对象

  • request 单个HTTP request请求中只会创建一个对象实例

  • session 单个HTTP session周期中只会创建一个对象实例

  • application 整个ServletContext周期内只有一个

  • websocket 整个websocket连接中中只有一个

aop:scoped-proxy用途

短作用域实例注入到长作用域实例中需要用到代理,因为长作用域的周期很长,例如scope为singleton的对象A,整个容器中初始化一次,它如果引用了一个短作用域的对象B(例如scope为request),就不能保证A是唯一的了,所以通过代理的方式来保证A不变,B的变化会通过代理对象对A隐藏掉。


<!-- an HTTP Session-scoped bean exposed as a proxy -->

<bean id="userPreferences" class="com.something.UserPreferences" scope="session">

    <!-- instructs the container to proxy the surrounding bean -->

    <aop:scoped-proxy/> 

</bean>



<!-- a singleton-scoped bean injected with a proxy to the above bean -->

<bean id="userService" class="com.something.SimpleUserService">

    <!-- a reference to the proxied userPreferences bean -->

    <property name="userPreferences" ref="userPreferences"/>

</bean>

spring-context-indexer 提高项目启动速度(spring5)

用法

  1. 在项目中添加依赖包

<dependencies>

    <dependency>

        <groupId>org.springframework</groupId>

        <artifactId>spring-context-indexer</artifactId>

        <version>5.1.4.RELEASE</version>

        <optional>true</optional>

    </dependency>

</dependencies>

  1. 打包

  2. 在jar包中会生成 spring.components 索引文件,如下


#

#Tue Jan 22 22:03:24 CST 2019

spring.core.learning.aware.ContextFrefreshedEventListener=org.springframework.stereotype.Component

spring.core.learning.aware.ClassLoaderAware=org.springframework.stereotype.Component

spring.core.learning.aware.ConsoleLoggingNotificationListener=org.springframework.stereotype.Component

spring.core.learning.aware.Listener=org.springframework.stereotype.Component

spring.core.learning.transaction.AccountService=org.springframework.stereotype.Component

spring.core.learning.aware.NotifyService=org.springframework.stereotype.Component

开发生产等环境隔离


@Configuration

public class ProfileConfig {

    @Bean("env")

    @Profile("dev")

    public Env devEnv() {

        return new Env("dev");

    }

    @Bean("prod")

    @Profile("prod")

    public Env productEnv() {

        return new Env("prod");

    }

    @Data

    @AllArgsConstructor

    public static class Env {

        String name;

    }

}

事件通知

用法

  1. 自定义事件类 extends ApplicationEvent

  2. 订阅者实现ApplicationListener<T>接口, T可以传递自定义的事件类

  3. 发布者实现ApplicationEventPublisherAware,通过ApplicationEventPublisher进行事件下发

示例


//事件

@Data

public class Notify extends ApplicationEvent {

    private String title;

    private String content;

    public Notify(Object source) {

        super(source);

    }

}


//生产者

public class NotifyService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher eventPublisherAware;

    public void notify(Notify notify) {

        log.info("publish notify event: {}", notify);

        this.eventPublisherAware.publishEvent(notify);

    }

    @Override

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {

        this.eventPublisherAware = applicationEventPublisher;

    }

}


//订阅者,或者用@EventListener注解

@Service

public class Listener implements ApplicationListener<Notify> {



    @Override

    public void onApplicationEvent(Notify event) {

        System.out.println("receive message: " + event.getTitle() + ", content:" + event.getContent());

    }

}

#常见问题

###循环依赖

循环依赖主要是产生的原因通过构造函数来实现DI注入时,被注入的对象同时需要注入本对象。例如以下配置,解决办法是尽量使用setter方式注入,来替代构造函数注入的方式。
`xml






<bean id="hefang" class="spring.core.learning.model.Student" name="hah">
    <property name="className" value="701"/>
    <property name="name" value="hefang"/>
    <property name="teacher" ref="wanglaoshi"/>
</bean>

`