本文介绍的内容如下

Java注入:@Configuration、@Bean

自动注入:

        XML:<component-scan/>

        Java:@ComponentScan

    @Repository

    @Service

    @Controller

    @Component

Profile:

        Java:@Profile

        XML:<beans profile="dev"

条件注解:

        @Conditional

Bean的生命周期:

        singleton、prototype、request、session

混合配置:

        @ImportResource

Java配置

Java配置本质上,就是使用一个Java类去代替xml配置,这种配置方式在SpringBoot中得到了广泛的使用。

1、引入的依赖及相关类

把 Bean 注入到 IOC 容器里面的方式有 @bean 注入_bean

2、创建实体类并创建getset方法

public class Book {
    private Integer id;
    private String name;
    private String author;
}

3、创建java配置类

import org.springframework.context.annotation.Bean;
    /**
    * 这个是Java配置类,它的作用类似于applicationContext.xml文件
    */
public class JavaConfig {
    /**
    * 返回一个JavaBean的方法就类似于applicationContext.xml中的一个bean标签
    *
    * <bean class="com.itbaizhna.Book" id="book"></bean>
    * @return    
    * 默认情况下,id就是方法名,可以通过@Bean注解的value或者name属性自定义方法名
    */
@Bean(name = "b1")
Book book(){
    return new Book();
    }
}

4、在入口方法处,加载Java配置

import org.junit.Before;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* 使用AnnotationConfigApplicationContext可以实现
* 基于Java的配置类加载Spring的应用上下文.避免使用application.xml进行配置。
* 在使用spring框架进行服务端开发时,个人感觉注解配置在便捷性,和操作上都优于是使用XML进行配置;
*/
public class Test {
    private AnnotationConfigApplicationContext ctx;
    @Before
    public void before(){
        ctx = new AnnotationConfigApplicationContext(JavaConfig.class);
    }
    @org.junit.Test
    public void test1() {
        Book book = (Book) ctx.getBean("book");
        System.out.println(book);
       Book book1 = ctx.getBean(Book.class);
        System.out.println(book1);
    }
    //在JavaConfig中添加@Bean(name = "b1")
    @org.junit.Test
    public void test2() {
        Book b1 = (Book) ctx.getBean("b1");
        System.out.println(b1);
    }
}

自动配置

前面这种配置方式,对于所有要使用的类都需要一个一个的配置。可以通过自动配置来简化Bean的配置。

XML配置实现

1、引入的依赖以及相关类

把 Bean 注入到 IOC 容器里面的方式有 @bean 注入_spring_02

2、创建user实体类并创建getset方法,重写tostring方法

import org.springframework.stereotype.Component;
/**
* @Component注解表示该类是一个bean,在项目启动时,该类会被自动扫描,
* 然后实例化并注册到Spring容器中去,实例默认的名字就是类名首字母小写
*
* 类似的注解,Spring一共提供了四个:
* 1. @Component,一般用在身份不明确的组件上
* 2. @Service,一般用在Service层
* 3. @Controller,一般用在控制层
* 4. @Repository,一般用在数据库访问层
*
* 但是,目前来说,这四个的功能基本一致,没有大的区别
*/
@Component
public class User {
    private Integer id;
    private String name;
    private String address;
}

创建person实体类

package com.tang.bean;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* Person的注解为@Component的时候,xml中只要有
* <bean class="com.tang.bean.Person" id="p" scope="prototype"/>就能执行
*
* Person的注解为@Service("p")的时候,xml中只要有
* <context:component-scan base-package="com.tang.bean"/>就能运行
*/
//@Component
@Service("p")
public class Person {
public void sayHello(String name){
    System.out.println("hello"+name);
}
}

3、创建xml配置类,标准写法可以进行包的精确扫描

<?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"
    xsi:schemaLocation="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.xsd">

    <!--可以在com.tang.bean后面加“,”,添加其他的-->
    <context:component-scan base-package="com.tang.bean"/>
    <!--<context:component-scan base-package="com.tang.bean ,com.tang.ser"/>-->
    <bean class="com.tang.bean.Person" id="p" scope="prototype"/>
    <!--标准写法-->
    <!--并且只响应了service的,没有响应Component的,所以会导致使用Component注解的用不了-->
    <!--<context:component-scan base-package="com.tang" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>-->
</beans>

4、在入口方法处,加载XML配置

import com.tang.bean.Person;
import com.tang.bean.User;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class main {
    private ClassPathXmlApplicationContext ctx;

    @Before
    public void before() {
        ctx = new ClassPathXmlApplicationContext("application.xml");
    }
    //使用标准写法后执行报错
    @Test
    public void test1() {
        User user = (User) ctx.getBean("user");//user要小写
        System.out.println(user);
    }

    //使用标准写法后
    @Test
    public void test2() {
        Person p = (Person) ctx.getBean("p");
        p.sayHello("zhangsan");
    }
}

Java配置和XML配置基本一致,唯一不同的地方就是包扫描的方式。

四个注解是一样的。

包扫描通过@ComponentScan来实现:

创建Java配置类,标准写法可以进行包的精确扫描

@Configuration//@Configuration用于定义配置类,可替换xml配置文件
//@ComponentScan(value = "com.tang.bean")简单写法
@ComponentScan(value = "com.tang.bean", useDefaultFilters = false, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Service.class)
})
public class JavaConfig {
}

然后再Main中引用java配置就可以了

 

Profile配置

在实际开发中,项目即将上线时,可能需要不停的在开发环境、生产环境、测试环境...之间进行切换。

数据库配置:url,username,password

redis:地址

mongodb:地址、用户名、密码

...

...

1、引入的依赖以及相关类

把 Bean 注入到 IOC 容器里面的方式有 @bean 注入_xml_03

2、创建相应的实体类

public class DateSource {
    private String url;
    private String username;
    private String password;
}
public class RedisConfig {
    private String url;
    private String password;
}

3、创建java配置类

import com.tang.bean.DateSource;
import com.tang.bean.RedisConfig;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Service;

@Configuration//@Configuration用于定义配置类,可替换xml配置文件
@ComponentScan(value = "com.tang.bean", useDefaultFilters = false, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Service.class)
})
public class JavaConfig {
    /**
    * @return
    * @Profile注解相当于一个标记,标记当前的dataSource是开发环境下的dataSource
    */
    @Bean("ds")
    @Profile("dev")
    DateSource devDs() {
        return new DateSource("jdbc:mysql:///dev", "dev", "dev");
    }

    @Bean("ds")
    @Profile("prod")
    DateSource prodDs() {
        return new DateSource("jdbc:mysql://123.99.88.77:3306/prod", "prod", "prod");
    }

    @Bean("rc")
    @Profile("dev")
    RedisConfig devRc() {
        return new RedisConfig("127.0.0.1", "123");
    }

    @Bean("rc")
    @Profile("prod")
    RedisConfig prodRc() {
        return new RedisConfig("123.33.44.55", "jflakjdkla");
    }
}

测试类    注意这里的顺序问题,需要首先设置当前环境,然后再去加载配置类。

import com.tang.bean.DateSource;
import com.tang.bean.RedisConfig;
import com.tang.config.JavaConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class test1 {
public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    //设置当前环境为开发环境(dev)
    ctx.getEnvironment().setActiveProfiles("dev");
    ctx.register(JavaConfig.class);
    ctx.refresh();
    DateSource ds = (DateSource) ctx.getBean("ds");
    System.out.println(ds);
    RedisConfig rc = (RedisConfig) ctx.getBean("rc");
    System.out.println(rc);
    }
}
结果
DateSource{url='jdbc:mysql:///dev', username='dev', password='dev'}
RedisConfig{url='127.0.0.1', password='123'}

4、创建xml配置类

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


<beans profile="dev">
<bean class="com.tang.bean.DateSource" name="ds">
<property name="username" value="root"/>
<property name="password" value="123"/>
<property name="url" value="jdbc:mysql:///123123213"/>
</bean>
</beans>
<beans profile="prod">
<bean class="com.tang.bean.DateSource" name="ds">
<property name="username" value="prod"/>
<property name="password" value="prod"/>
<property name="url" value="jdbc:mysql:///dev"/>
</bean>
</beans>
</beans>

测试类 注意,beans标签要写在其他标签的后面。使用步骤和Java配置类似:

import com.tang.bean.DateSource;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test2 {
public static void main(String[] args) {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
    ctx.getEnvironment().setActiveProfiles("prod");
    ctx.setConfigLocation("applicationContext.xml");
    ctx.refresh();
    DateSource ds = (DateSource) ctx.getBean("ds");
    System.out.println(ds);
    }
}
结果
DateSource{url='jdbc:mysql:///dev', username='prod', password='prod'}

条件注解

Profile实际上就是条件注解的一种特殊形式,即条件注解更加灵活,用户可以根据各种不同的条件使用不同的Bean。

条件注解在SpringBoot中使用非常广泛。SpringBoot中提供了许多自动化的配置,例如数据库配置,SpringBoot使用条件注解提前配置好许多常用的类,使用条件注解,在某一个条件满足时,这些配置就会生效。

1、引入的依赖以及相关类

把 Bean 注入到 IOC 容器里面的方式有 @bean 注入_Java_04

2、定义接口

public interface ShowCmd {
    String show();
}

3、创建相关的实体类实现接口

public class WinShowCmd implements ShowCmd{
    @Override
    public String show() {
        return "Ws";
    }
}
public class LinuxShowCmd implements ShowCmd {
    @Override
    public String show() {
        return "Ls";
    }
}

4、定义条件

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class WinCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        String osName = conditionContext.getEnvironment().getProperty("os.name");
        return osName.toLowerCase().contains("window");
    }
}
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata    annotatedTypeMetadata) {
        String osName = conditionContext.getEnvironment().getProperty("os.name");
        return osName.toLowerCase().contains("linux"); 
    }
}

5、在java中配置Bean

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan(value = "com.tang")
public class JavaConfig {

    @Bean("cmd")
    @Conditional(WinCondition.class)
    ShowCmd win() {
        return new WinShowCmd();
    }

    @Bean("cmd")
    @Conditional(LinuxCondition.class)
    ShowCmd linux() {
        return new LinuxShowCmd();
    }
}

6、使用

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(JavaConfig.class);
        ctx.refresh();
        ShowCmd cmd = (ShowCmd) ctx.getBean("cmd");
        String show = cmd.show();
        System.out.println(show);
    }
}

7、结果

Ws

 

Bean的作用域

bean的作用域有四种,常用的有两种:

1.prototype,每次请求,都是一个新的Bean

2.singleton,bean是单例的

3.request,在一次请求中,bean的声明周期和request同步

4.session,bean的生命周期和session同步

在spring的配置中,默认情况下,bean都是单例的(singleton)。无论获取多少次,获取到的都是同一个bean。修改为prototype。

定义方式如下:

@Component
@Scope(value = "prototype")
public class User {
    private Integer id;
    private String name;
    private String address;
}

在xml中配置方式如下:

<bean class="com.itbaizhan.bean.Person" id="p" scope="prototype"/>
@Test
    public void test1() {
        User user = (User) ctx.getBean("user");//user要小写
        User user2 = (User) ctx.getBean("user");
        System.out.println(user==user2);
        System.out.println(user);
    }

加上这个后,创建的两个user对象就是不同的了

混合配置

混合配置就是XML配置+Java配置

在混合配置中,主要通过如下注解向Java配置中导入XML配置:

@ImportResource(locations = "classpath:applicationContext.xml")