0x02.IoC容器配置

[TOC]

Spring配置方案

(不仅仅是Ioc的配置)
从前文容器的具体实现已经知道,配置容器或者说配置应用上下文有多种方式,如Java类,来自文件系统或来自classpath的的xml文件,还有Spring基于注解的自动配置(依赖前两种开启自动扫描)。

总结下来,对于Spring最核心和最基础的自动装配功能(集成依赖注入),主要有以下三种装配机制:

  • 在XML中显式配置
  • 在java类中显式配置
  • 隐式bean发现机制(自动扫描装配)

三种方式并非互斥,甚至三者可以共同使用。
以下记录三种方式配置IOC容器。

自动化装配

自动化装配的思路是:

  1. 指明要被容器管理的bean
  2. bean之间的依赖关系

定义Bean的方式和定义bean之间的依赖注入都有两种方式:基于xml和基于注解。也就是说可以使用xml或注解来定义bean,可以使用xml或注解来定义bean之间的依赖注入关系。这两个是分开的,你可以使用xml定义所有的bean,然后使用注解的形式来注入依赖(需要开启注解配置),也可以使用注解来定义bean、然后使用注解来定义依赖注入。(没有使用注解定义bean再使用xml定义依赖注入这种方式);

定义bean的方式是在Spring读取配置元数据这个时期需要处理的事情,所以和这个过程相关的是取得BeanDefinition的过程,是和BeanFactoryPostProcessor相关的;而注入依赖是BeanPostProcessor做的事情,BeanPostProcessor是在bean实例化之后介入bean的生命周期,为对象装配属性;构造器注入的bean在实例化的时候调用的是有参构造器,构造器参数肯定在此前实例化完成,所以这步依赖的注入在实例化bean时完成。

使用xml定义bean方式即为在xml中使用<bean>标签来配置,在xml中定义注入关系或者开启注解使用注解来配置依赖关系,开启注解的方法是在xml中添加<context:annotation-config/>,然后使用如@Autowired,@PostConstruct,@PreDestroy,@Inject,@Named,@Required来配置注入;
使用注解的形式定义bean实际上分为两种,一种是集中式的定义在Java类中,另一种是分散在各个包中的bean类定义上,前者就是后面要说的基于java类的配置,后者是基于Spring发现机制的隐式配置。前者在JavaConfig类中使用@Bean来定义bean,然后使用前述的注解配置依赖关系;后者则是有一系列的注解来定义bean,且这些注解是在具体要定义成bean的类中加的,如@Component@Service@Controller@Repository,声明此bean交由容器管理和装配属性,另外给需要由容器注入的属性加上类似@Autowired、@Resource、@Value的注解,指明依赖关系。

IOC常用注解

@Required

这个注释表明,bean属性必须在配置时填充,通过bean定义中的显式属性值或通过自动装配。

@Component

声明此class为一个Spring组件,在class上使用,可以在注解后面指定beanID,@Component是声明为Spring组件最基础的注解,在其基础上还有@Controller、@Service、@Repository等语义更加细粒的注解形式。

Spring提供了进一步的模板注释:@Component, @Service和@Controller。@Component是任何spring管理组件的通用原型。@Repository、@Service和@Controller分别是针对更具体的用例(例如,在持久性、服务和表示层)的@Component的专门化。因此,您可以使用@Component对组件类进行注释,但是通过使用@Repository、@Service或@Controller对它们进行注释,您的类更适合通过工具进行处理或与方面关联。例如,这些模板注释是切入点的理想目标。在Spring框架的未来版本中,@Repository、@Service和@Controller也可能包含额外的语义。因此,如果您正在为您的服务层选择使用@Component还是使用@Service,那么@Service显然是更好的选择。类似地,如上所述,@Repository已经被支持作为持久性层中自动异常转换的标记。

  • Meta-annotations
    例如@Component是@Service的元注解,也就是这种更细粒度的注解也是基于基础注解的。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Spring will see this and treat @Service in the same way as @Component
public @interface Service {

    // ....
}

Meta-annotations can also be combined to create composed annotations. For example, the @RestController annotation from Spring MVC is composed of @Controller and @ResponseBody.

@Autowired

声明需要注入一个属性 | 在属性,构造器,setter上使用

As of Spring Framework 4.3, an @Autowired annotation on a constructor is no longer necessary if the target bean only defines one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use.
The required attribute of @Autowired is recommended over the @Required annotation.

另外Spring支持Java依赖注入规范(Java Dependency Injection)提供的注解来替代Spring的注解,如使用@Named替换@Component,使用@Inject替代@Autowired.

@Qualifier

限定beanID,和@Autowired组合使用限定注入的BeanID,也可以和@Component组合使用,设置当前BeanID

@Resource

和Autowired相似,@Autowired按byType自动注入,而@Resource默认按byName自动注入。@Resource有两个属性是比较重要的,分别是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。

@Primary

@Primary表示当多个bean可以自动装配到单值依赖项时,应该优先选择特定的bean。如果候选者中只存在一个“主”bean,则它将是自动装配的值。此注解用来标明bean是primary,一般和@Bean结合使用,还可以在xml中bean定义中primary="true"标明此bean是primary。使用@Qualifier("main")拥有更细的粒度;

@PostConstruct和@PreDestroy

这两个是lifecycle annotations,对应initialization callbacks和destruction callbacks。在Spring 2.5中引入,对这些注释的支持提供了初始化回调和销毁回调中描述的另一种替代方法。 如果CommonAnnotationBeanPostProcessor在Spring ApplicationContext中注册,则在生命周期的同一点调用承载这些注释之一的方法,作为相应的Spring生命周期接口方法或显式声明的回调方法。

@Lazy

可以放在bean定义一起来延迟创建bean,也可以和@Autowired或@Inject一起使用来延迟注入依赖

配置注入关系的注解的使用范围

@Autowired, @Inject, @Resource, and @Value annotations are handled by Spring BeanPostProcessor implementations which in turn means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be 'wired up' explicitly via XML or using a Spring @Bean method.

1.基于XML文件配置自动装配方式

  • 配置思路

使用xml配置声明bean,在xml中配置DI或使用注解配置DI

XML定义bean和DI

  • 示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 配置一个bean -->
    <!--如果没有指明ID,则默认ID为“com.springinaction.ioc.BraveKnight#0”-->
    <bean id="knight" class="com.springinaction.ioc.BraveKnight">
        <!--给构造函数传递参数,没有的话则调用默认构造方法 -->
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="com.springinaction.ioc.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}" />
    </bean>
    <bean id="minstrel" class="com.springinaction.aop.Minstrel">
        <constructor-arg value="#{T(System).out}" />
    </bean>
</beans>
  • 启动容器测试
    ApplicationContext context = new ClassPathXmlApplicationContext(
                "classpath:spring.xml");
    // 也可选择FileSystemXmlApplicationContext类来定义上下文启动容器
    BraveKnight knight = context.getBean(BraveKnight.class);
    knight.fight();

需要注意的是,Spring在遇到<bean>创建bean时,调用的是默认构造器(如果没有定义构造器注入的话);

XML定义bean,注解配置DI

  • 示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="
    http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- 配置一个bean -->
    <bean id="testBean" class="com.springinaction.ioc.beaninject.TestBean"></bean>
    <!-- 依赖TestBean,但是依赖关系定义在类的注解中 -->
    <bean id="testBean2" class="com.springinaction.ioc.beaninject.TestBean2"></bean>
    <!-- 启用注解支持 -->
    <context:annotation-config />
</beans>
  • java类中使用注解配置DI
public class TestBean2 {

    public TestBean2() {
        System.out.println("TestBean2 default constructor");
    }

    private TestBean t;
    // 配置DI
    @Autowired
    public TestBean2(TestBean t) {
        System.out.println("TestBean2 set t in constructor");
        this.t = t;
    }

    // ...
}
  • 启动容器测试
    @Test
    public void testDefineBeanInXMLButDIbyAnnotation() {
        context = new ClassPathXmlApplicationContext(
                "classpath:com/springinaction/ioc/beaninject/spring.xml");
        TestBean2 t2 = context.getBean(TestBean2.class);
        System.out.println(t2.getT());
    }

2.基于Java类配置自动装配方式

Java类中定义bean,类中配置DI。依赖注解@Bean和@Configuration。

@Bean和@Configuration

@Bean和@Configuration是基于Java配置容器的核心组件。@Bean用来注解方法,用来指明一个实例化、配置和初始化一个由Spring容器管理的新对象的方法。@Bean的语义和xml中<bean>的作用类似。@Bean可以和@Component一起使用,但是一般是和@Configuration一起使用。

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
    /**
     * The name of this bean, or if plural, aliases for this bean. If left unspecified
     * the name of the bean is the name of the annotated method. If specified, the method
     * name is ignored.
     */
    String[] name() default {};
    /**
     * Are dependencies to be injected via convention-based autowiring by name or type?
     */
    Autowire autowire() default Autowire.NO;
    String initMethod() default "";
    String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}

@Bean的使用


@Configuration
public class AppConfig {
    @Bean(name = "myFoo")

    @Bean(initMethod = "init")
    public Foo foo() {
        return new Foo();
    }

    @Bean(destroyMethod = "cleanup") //bean默认会调用类的公共close或shutdown方法作为destoryMethod,如果不需要可以使用 @Bean(destroyMethod="")
    @Bean(name = { "dataSource", "subsystemA-dataSource", "subsystemB-dataSource" })  // alias
    @Description("Provides a basic example of a bean")
    public Bar bar() {
        return new Bar();
    }

    //  定义scope
    @Bean
    @Scope("prototype")
    public Encryptor encryptor() {
        // ...
    }
    // scoped-proxy
    // an HTTP Session-scoped bean exposed as a proxy
    @Bean
    @SessionScope
    public UserPreferences userPreferences() {
        return new UserPreferences();
    }
}

@Configuretion的使用

@Configuretion注解用来注解一个class,表明它是一个bean定义的配置类。此外,@Configuration类允许通过简单地调用同一类中的其他@Bean方法来定义bean间的依赖关系。

This method of declaring inter-bean dependencies only works when the @Bean method is declared within a @Configuration class. You cannot declare inter-bean dependencies using plain @Component classes.

All @Configuration classes are subclassed at startup-time with CGLIB.In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.

There is another way to achieve the same result. Remember that @Configuration classes are ultimately just another bean in the container: This means that they can take advantage of @Autowired and @Value injection etc just like any other bean!

@Bean的lite模式

@Bean注解的方法所在的类没有使用@Configuration注解的情况,就是lite模式。这种模式下,不能在类中定义DI关系(直接调用其他的@Bean方法不是使用的Spring容器注入的bean,而是新创建的对象),此场景下@Bean方法定义的是bean的工厂方法。(有一种prototype的语义)

常规Spring组件中的@Bean方法与Spring @Configuration类中的对应方法处理方式不同。不同之处在于,并没有使用CGLIB增强@Component类来拦截方法和字段的调用。CGLIB代理是在@Configuration类中的@Bean方法中调用方法或字段的方法,它为协作对象创建bean元数据引用;这些方法不是使用普通的Java语义来调用的,而是通过容器来提供Spring bean通常的生命周期管理和代理,即使是通过对@Bean方法的编程调用来引用其他bean时也是如此。相反,在普通的@Component类中调用@Bean方法中的方法或字段具有标准的Java语义,不应用特殊的CGLIB处理或其他约束。

注意,对静态@Bean方法的调用永远不会被容器截获,甚至在@Configuration类中也不会被拦截(参见上面的内容)。这是由于技术限制:CGLIB子类化只能覆盖非静态方法。因此,直接调用另一个@Bean方法将具有标准的Java语义,从而直接从factory方法本身返回一个独立的实例。

最后,请注意,单个类可以为同一个bean保存多个@Bean方法,作为根据运行时可用依赖项使用的多个工厂方法的安排。这与在其他配置场景中选择“greediest”构造函数或工厂方法的算法是相同的:在构建时将选择具有最大数量可满足依赖性的变体,类似于容器在多个@Autowired构造

public class SpringBeanInjectConfig4TestBean {

    @Bean
    public TestBean testBean() {
        return new TestBean();
    }

    @Bean
    public TestBean2 testBean2() {
        return new TestBean2(testBean());
    }
}

    @Test
    public void testJavaBasedConfig() {
        context = new AnnotationConfigApplicationContext(SpringBeanInjectConfig4TestBean.class);
        TestBean2 t2 = context.getBean(TestBean2.class);
        TestBean t = context.getBean(TestBean.class);
        org.junit.Assert.assertEquals(t, t2.getT()); // error
    }

配置示例

  1. 创建配置类
  2. 使用注解@Bean声明bean
  3. 借助JavaConfig注入
  • config类
@Configuration
public class SpringBeanInjectConfig4TestBean {

    @Bean
    public TestBean testBean() {
        return new TestBean();
    }

    @Bean
    public TestBean2 testBean2() {
        return new TestBean2(testBean());
    }
}
  • bean
public class TestBean2 {
    private TestBean t;
    public TestBean2(TestBean t) {
        System.out.println("TestBean2 set t in constructor");
        this.t = t;
    }
  // ...
}
  • 启动容器
    @Test
    public void testJavaBasedConfig() {
        context = new AnnotationConfigApplicationContext(
                SpringBeanInjectConfig4TestBean.class);
        TestBean2 t2 = context.getBean(TestBean2.class);
        System.out.println(t2.getT());
    }

还可以:

    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.register(AppConfig.class, OtherConfig.class);
    ctx.register(AdditionalConfig.class);
    ctx.refresh();

@Bean注解声明此方法返回类型对应的bean注册为Spring Bean,且默认方法名为beanID。Spring会自动调用@Bean注解的方法中的方法创建对象和注入依赖。这个方式更像是手动注入依赖和创建对象,因为需要手动去写new,以及传入属性。

@Bean is a method-level annotation and a direct analog of the XML <bean/> element. @Bean带注释的方法可以有任意数量的参数来描述构建该bean所需的依赖关系。

@Bean注解的方法是作为bean的factory-method来创建bean的,类似在xml中定义factory-method。使用此方式的bean不能在配置类的外部使用@Autowired等配置DI。只能在config类中配置,配置方式有两种:一是直接在@Bean注解的方法内调用其他@Bean的方法,或者使用方法参数来注入:

    @Bean
    public TestBean2 testBean2(TestBean t) {
        return new TestBean2(t);
    }

3.基于隐式bean发现机制的自动装配方式

使用此方式不需要使用xml或java类明确集中式地定义bean,而是使用注解声明一个class是bean,然后通过Spring的自动扫描机制将其装入容器中,此方式下的DI也通过注解的形式配置。

此方式基于注解和Spring detect机制;需要借助前两种方式来开启包扫描功能才能使用注解来让Spring发现,此方式相较前两种的集中式配置方案,它的配置是分散在各个类中的。

“Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.”

Excerpt From: Rod Johnson. “Spring Framework Reference Documentation.” iBooks.

bean声明

  • 使用Spring 模板注解(@Component, @Repository, @Service, and @Controller)是,声明一个bean
  • bean附加属性如name,scope
@Scope("prototype")
@Repository("myrepos")
public class MovieFinderImpl implements MovieFinder {
    // ...
}
  • @Qualifier可以和@Component一起使用来设置name

Spring组件模型元素vs JSR-330变体

Spring javax.inject.*
@Autowired @Inject
@Component @Named / @ManagedBean
@Scope("singleton") @Singleton
@Qualifier @Qualifier / @Named
@Value -
@Required -
@Lazy -
ObjectFactory Provider

自动扫描

自动扫描的配置需要借助Java类或者是XML来配置开启自动扫描以及扫描的包目录;

基于Java类配置包扫描

示例:

@Configuration
@ComponentScan // 配置自动扫描,默认是本类所在的包及子包
public class SpringConfig {

    //...
}

启动容器,以java配置类定义应用上下文:

public static void main(String[] args) {
        ApplicationContext context = null;
        // 使用java类配置方式
        context = new AnnotationConfigApplicationContext(com.springinaction.SpringConfig.class);
        // ...
        // or
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.scan("com.acme");
        ctx.refresh();
    }

@Configuration

从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

如果像示例一样在main方法中直接指明了使用AnnotationConfigApplicationContext来从此类定义应用上下文,可以不加这个注解。

@ComponentScan
  • 这个注解默认情况下开启扫描本类所在的包以及子包;
  • @ComponentScan("com.test"):指定包名
  • @ComponentScan(basePackages="com.test")
  • @ComponentScan(basePackages={"com.test","com.test2"})
  • @ComponentScan(basePackageClasses={A.class,B.class}):类所在包及子包
扫描过滤
  • 示例
@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}
  • 支持的格式
Filter Type Example Expression
annotation (default) org.example.SomeAnnotation
assignable org.example.SomeClass
aspectj org.example..*Service+
regex org\.example\.Default.*

还可以实现org.springframework.core.type .TypeFilter接口自定义过滤器

基于xml配置包扫描

示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="
    http://www.springframework.org/schema/context" xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 自动扫描web包 ,将带有注解的类 纳入spring容器管理 -->
    <context:component-scan base-package="com.test.*"></context:component-scan>
</beans>

使用了<context:annotation-config>自动包含了<context:annotation-config>

扫描过滤
<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

启动容器定义应用上下文:

public static void main(String[] args) {
        ApplicationContext context = null;
        // 使用xml配置文件方式
        context = new ClassPathXmlApplicationContext("spring.xml");
        
}

如此,基本的基于注解的自动扫描装配就可用了。
使用自动扫描机制实际上隐式地包含了AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor,它们是自动扫描装配的支撑。

4.混合配置方式

JavaConfig引用XML和其他JavaConfig

@Configuration
@Import(BConfig.class)
public class AConfig{
    @Bean
    //...
}
@Configuration
@ImportResource("classpath:spring.xml")
public class BConfig{
    //..
}

@Configuration
@Import({AConfig.class,BConfig.class})
public class AllConfig{
    
}

xml中引用JavaConfig

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="...">
 <!--引用xml-->
 <import resource="spring.xml"/>
 <!--引用JavaConfig-->
 <bean class=com.JavaConfig.class/>
 
</beans>

参考资料

[1] Spring In Action

[2] Spring Framework Reference Documentation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容

  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,689评论 2 22
  • 1.1 Spring IoC容器和bean简介 本章介绍了Spring Framework实现的控制反转(IoC)...
    起名真是难阅读 2,566评论 0 8
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,566评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,714评论 6 342
  • 1.倾听习惯。 2.主动打招呼。 3.每月赛事。足球赛和篮球赛 4.语言。儿歌,手指谣餐前,童谣,成语故事,复述故...
    静泽福淼阅读 461评论 0 0