Spring5注解驱动(六)

5. 自动装配

5.1. @Autowired&@Qualifier&@Primary

在原来,我们就是使用@Autowired的这个注解来进行自动装配;

现在有一个BookController 类

package com.hutu.controller;

import com.hutu.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class BookController {

    @Autowired
    private BookService bookService;
}

还有一个BookService:

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Autowired
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

还有一个BookDao:为了在自动装配的是哪一个,我们给这个BookDao加上一个标识属性:lable ,如果是通过包扫描到IOC容器中,标识为1,如果是在配置类里面通过@Bean装配的标识为2:

package com.hutu.dao;

import org.springframework.stereotype.Repository;

/**
 * 在IOC容器里面默认就是类名的首字母小写
 */
@Repository
public class BookDao {

    private String lable = "1";

    public String getLable() {
        return lable;
    }

    public void setLable(String lable) {
        this.lable = lable;
    }

    @Override
    public String toString() {
        return "BookDao{" +
                "lable='" + lable + '\'' +
                '}';
    }
}

配置类: MainConfigOfAutowired

package com.hutu.config;

import com.hutu.dao.BookDao;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * 自动装配:
 *      Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值
 * 1) @Autowired:自动注入
 *      (1)默认优先按照类型去容器中去找对应的组件:applicationContext.getBean(BookDao.class);如果找到了则进行赋值;
 *      public class BookService {
 *          @Autowired
 *          BookDao bookDao;
 *      }
 */
@Configuration
@ComponentScan({"com.hutu.controller","com.hutu.service","com.hutu.dao"})
public class MainConfigOfAutowired {

    @Bean("bookDao2")
    public BookDao bookDao() {
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }
}

再来写上一个测试类:为了区分是装配的是通过包扫描的方式还是通过在配置类里面进行装配的:

@Test
public void test02() {
    ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
    BookService bookService = context.getBean(BookService.class);
    System.out.println(bookService);

}

测试结果

BookService{bookDao=BookDao{lable='1'}}

自动装配: Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值

@Autowired:自动注入

(1)默认优先按照类型去容器中去找对应的组件:applicationContext.getBean(BookDao.class);如果找到了则进行赋值;

(2)如果找到了多个相同类型的组件,再将属性的名称作为组件的id去容器中查找 applicationContext.getBean(“bookDao”)

(3)@Qualifier("bookDao"):使用 @Qualifier 指定需要装配的组件的id,而不是使用属性名;

(4)自动装配默认一定要将属性赋值好,没有就会报错,可以使用@Autowired(required = false);来设置为非必须的;

(5)可以利用@Primary:让Spring在进行自动装配的时候,默认使用首选的bean; 也可以继续使用@Qualifier("bookDao")来明确指定需要装配的bean的名字。

@Service
public class BookService {

    @Autowired
    private BookDao bookDao;
}

如果我们想要装配bookDao2:我们就把属性名改成bookDao2就可以了:

public class BookService {
    @Autowired
    BookDao bookDao2;
}

就可以这样来写

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Autowired
    private BookDao bookDao2;

    public void print() {
        System.out.println(bookDao2);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

测试结果

BookService{bookDao=BookDao{lable='2'}}

虽然,在属性名写了bookDao2,但是,我就想要装配bookDao;实际上也是可以的:我们可以使用 @Qualifier这个注解 @Qualifier("bookDao"):使用 @Qualifier 指定需要装配的组件的id,而不是使用属性名

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Qualifier("bookDao")
    @Autowired
    private BookDao bookDao2;

    public void print() {
        System.out.println(bookDao2);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

再来测试:发现又装配了bookDao了

BookService{bookDao=BookDao{lable='1'}}

而当我们的容器里面没有一个对应的bean的时候,这个时候,就是会报一个错

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘bookService’: Unsatisfied dependency expressed through field ‘bookDao2’; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.ldc.dao.BookDao’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=bookDao), @org.springframework.beans.factory.annotation.Autowired(required=true)}

那可不可以在使用自动装配的时候,这个bean不是必须的呢?如果容器里面没有对应的bean,我就不装配,实际上也是可以的:我们要@Autowired注解里面添加required = false这个属性@Autowired(required = false)

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Qualifier("bookDao")
    @Autowired(required = false)
    private BookDao bookDao2;

    public void print() {
        System.out.println(bookDao2);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

再来运行测试方法,测试结果为

BookService{bookDao=BookDao{lable='1'}}

还可以利用一个注解来让Spring在自动装配的时候,首选装配哪个bean:@Primary

package com.hutu.config;

import com.hutu.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * 自动装配:
 *      Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值
 * 1) @Autowired:自动注入
 *      (1)默认优先按照类型去容器中去找对应的组件:applicationContext.getBean(BookDao.class);如果找到了则进行赋值;
 *      public class BookService {
 *          @Autowired
 *          BookDao bookDao;
 *      }
 */
@Configuration
@ComponentScan({"com.hutu.controller","com.hutu.service","com.hutu.dao"})
public class MainConfigOfAutowired {

    @Primary
    @Bean("bookDao2")
    public BookDao bookDao() {
        BookDao bookDao = new BookDao();
        bookDao.setLable("2");
        return bookDao;
    }
}

当然明确指定的注解也是不能用了:@Qualifier("bookDao")

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

//    @Qualifier("bookDao")
    @Autowired(required = false)
    private BookDao bookDao2;

    public void print() {
        System.out.println(bookDao2);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao2 +
                '}';
    }
}

这个时候再来运行测试方法,测试结果如下:这个时候,Spring就首选装配了标注了@Primary注解的bean:

BookService{bookDao=BookDao{lable='2'}}

把装配的时候的属性名也变一下

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

//    @Qualifier("bookDao")
    @Autowired(required = false)
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

再来看看测试结果:还是装配了标注了@Primary注解的bean

BookService{bookDao=BookDao{lable='2'}}

如果是使用了@Qualifier("bookDao")明确指定了的:那还是按照明确指定的bean来进行装配

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class BookService {

    @Qualifier("bookDao")
    @Autowired(required = false)
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

测试结果

BookService{bookDao=BookDao{lable='1'}}

5.2. @Resource&@Inject

Spring还支持使用@Resource(JSR250)和@Inject(JSR330)

  • (1)@Resource:可以和@Autowired一样实现自动的装配,默认是按照组件的名称来进行装配,没有支持@Primary 也没有支持和@Autowired(required = false)一样的功能

  • (2)@Inject:需要导入javax.inject的包,和@Autowired的功能一样,没有支持和@Autowired(required = false)一样的功能

AutowiredAnnotationBeanPostProcessor是用来解析完成自动装配的功能的

@Autowired:是Spring定义的 @Resource 和 @Inject都是java的规范


  • @Resource 的使用

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class BookService {

    @Resource
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

测试方法

@Test
public void test02() {
    ApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);
    BookService bookService = context.getBean(BookService.class);
    System.out.println(bookService);

}

BookService{bookDao=BookDao{lable='1'}}

BookService{bookDao=BookDao{lable='1'}}

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class BookService {

    @Resource(name = "bookDao2")
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

BookService{bookDao=BookDao{lable='2'}}

@Inject的使用

导入jar包:

    <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
     <dependency>
         <groupId>javax.inject</groupId>
         <artifactId>javax.inject</artifactId>
         <version>1</version>
     </dependency>

可以这样来使用

package com.hutu.service;

import com.hutu.dao.BookDao;
import org.springframework.stereotype.Service;
import javax.inject.Inject;

@Service
public class BookService {

    @Inject
    private BookDao bookDao;

    public void print() {
        System.out.println(bookDao);
    }

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}

进行测试:发现也是可以支持@Primary的功能的

BookService{bookDao=BookDao{lable='2'}}

5.3. 方法、构造器位置的自动装配

@Autowired这个注解点进去看一下源码: 可以发现这个注解可以标注的位置有:构造器,参数,方法,属性;都是从容器中来获取参数组件的值

@Target({ElementType.CONSTRUCTOR
    	 , ElementType.METHOD
            , ElementType.PARAMETER
    	, ElementType.FIELD
    	, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

@Autowired注解标注在方法上:

用的最多的方式就是在@Bean注解标注的方法的参数,这个参数就是会从容器中获取,在这个方法的参数前面可以加上@Autowired注解,也可以省略,默认是不写@Autowired,都能自动装配

Car.java

package com.hutu.boot01.bean;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

public class Car2 implements InitializingBean, DisposableBean {

    public Car2() {
        System.out.println("car2 无参构造");
    }


    @Override
    public void destroy() throws Exception {
        System.out.println("car2...destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("car2...afterPropertiesSet...");
    }
}

Boss.java

package com.hutu.boot01.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 默认在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
 */
@Component
public class Boss {

    private Car2 car2;

    public Car2 getCar2() {
        return car2;
    }

    /**
     * 标注在方法上,Spring容器在创建当前对象的时候,就会调用当前方法完成赋值;
     * 方法使用的参数,自定义类型的值从IOC容器里面进行获取
     *
     * @param car2
     */
    @Autowired
    public void setCar(Car2 car2) {
        this.car2 = car2;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car2=" + car2 +
                '}';
    }
}
package com.hutu.config;

import com.hutu.dao.BookDao;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * 自动装配:
 *      Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值
 * 1) @Autowired:自动注入
 *      (1)默认优先按照类型去容器中去找对应的组件:applicationContext.getBean(BookDao.class);如果找到了则进行赋值;
 *      public class BookService {
 *          @Autowired
 *          BookDao bookDao;
 *      }
 */
@Configuration
//@ComponentScan({"com.hutu.controller","com.hutu.service","com.hutu.dao","com.hutu.bean"})
@ComponentScan({"com.hutu.bean"})
public class MainConfigOfAutowired {

//    @Primary
//    @Bean("bookDao2")
//    public BookDao bookDao() {
//        BookDao bookDao = new BookDao();
//        bookDao.setLable("2");
//        return bookDao;
//    }
}

测试

package com.hutu.boot01;

import com.hutu.boot01.bean.Boss;
import com.hutu.boot01.bean.Car2;
import com.hutu.boot01.config.MainConfigOfAutowired;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {

    @Test
    public void test01() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

        Boss boss = context.getBean(Boss.class);
        System.out.println(boss);
        Car2 car2 = context.getBean(Car2.class);
        System.out.println(car2);
    }

}

结果

Boss{car2=com.hutu.boot01.bean.Car2@4ebea12c}
com.hutu.boot01.bean.Car2@4ebea12c

@Autowired注解标注在构造器上,默认加在IOC容器中的组件,容器启动的时候会调用无参构造器创建对象,再进行初始化赋值操作,构造器要用的组件,也都是从容器中来获取: 注意:如果组件只有一个有参的构造器,这个有参的构造器的 @Autowired注解可以省略,参数位置的组件还是可以自动从容器中获取

Boss.java 添加有参构造器

package com.hutu.boot01.bean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 默认在ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
 */
@Component
public class Boss {

    private Car2 car2;

    @Autowired
    public Boss(Car2 car2){
        this.car2 = car2;
        System.out.println("Boss的有参构造器"+car2);
    }

    public Car2 getCar2() {
        return car2;
    }

    /**
     * 标注在方法上,Spring容器在创建当前对象的时候,就会调用当前方法完成赋值;
     * 方法使用的参数,自定义类型的值从IOC容器里面进行获取
     *
     * @param car2
     */
    @Autowired
    public void setCar(Car2 car2) {
        this.car2 = car2;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car2=" + car2 +
                '}';
    }
}

测试

@Test
public void test01() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

    Boss boss = context.getBean(Boss.class);
    System.out.println(boss);
    Car2 car2 = context.getBean(Car2.class);
    System.out.println(car2);
}

结果

Boss的有参构造器com.hutu.boot01.bean.Car2@76a2ddf3
    
Boss{car2=com.hutu.boot01.bean.Car2@76a2ddf3}
com.hutu.boot01.bean.Car2@76a2ddf3    

标在构造器上:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还说可以自动从容器中获取。

Color.java

package com.hutu.boot01.bean;

public class Color {

    private Car2 car2;

    public Car2 getCar2() {
        return car2;
    }

    public void setCar2(Car2 car2) {
        this.car2 = car2;
    }

    @Override
    public String toString() {
        return "Color{" +
                "car2=" + car2 +
                '}';
    }
}
package com.hutu.boot01.config;

import com.hutu.boot01.bean.Car2;
import com.hutu.boot01.bean.Color;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.hutu"})
public class MainConfigOfAutowired {


    /**
     * @Bean 标注的方法创建对象的时候,方法参数的值从容器中获取
     * @param car2
     * @return
     */
    @Bean
    public Color color(Car2 car2){
        Color color = new Color();
        color.setCar2(car2);
        return color;
    }
}

测试

package com.hutu.boot01;

import com.hutu.boot01.bean.Boss;
import com.hutu.boot01.bean.Car2;
import com.hutu.boot01.bean.Color;
import com.hutu.boot01.config.MainConfigOfAutowired;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IOCTest_Autowired {

    @Test
    public void test01() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

        Boss boss = context.getBean(Boss.class);
        System.out.println(boss);
        Car2 car2 = context.getBean(Car2.class);
        System.out.println(car2);
        System.out.println("===============");
        Color color =  context.getBean(Color.class);
        System.out.println(color);
    }

}

结果

Boss{car2=com.hutu.boot01.bean.Car2@545b995e}
com.hutu.boot01.bean.Car2@545b995e
===============
Color{car2=com.hutu.boot01.bean.Car2@545b995e}


总结:

@Autowired:构造器,参数,方法,属性,都是从容器中获取参数组件的值。

(1)【标注在方法位置】:@Bean+方法参数,参数从容器中获取。

5.4. Aware注入Spring底层组件&原理

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext、BeanFactory…) 自定义组件实现xxxAware接口就可以实现,在创建对象的时候,会调用接口规定的方法注入相关的组件; 把Spring底层的一些组件注入到自定义的bean中;

xxxAware等这些都是利用后置处理器的机制,比如ApplicationContextAware 是通过ApplicationContextAwareProcessor来进行处理的;

例如之前写的这个,实现ApplicationContextAware 接口,里面有一个setApplicationContext方法

package com.hutu.boot01.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;

@Component
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("传入的IOC:" + applicationContext);
        this.applicationContext = applicationContext;
    }


    @Override
    public void setBeanName(String name) {
        System.out.println("当前bean的名字:" + name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String s = resolver.resolveStringValue("你好${os.name}");
        System.out.println("解析的字符串:" + s);
    }
}

结果

当前bean的名字:red
解析的字符串:你好Windows 10
传入的IOC:org.springframework.context.annotation.AnnotationConfigApplicationContext@2ef9b8bc, started on Fri Dec 16 10:02:43 CST 2022

5.5. @Profile环境搭建

mysql驱动

<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

<dependency>
          <groupId>c3p0</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.1.2</version>
      </dependency>


<!--德鲁伊数据库连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.10</version>
</dependency>

完整的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.hutu</groupId>
    <artifactId>boot01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>boot01</name>
    <description>boot01</description>
    <properties>
        <java.version>1.8</java.version>
<!--        <mysql.version>5.1.43</mysql.version>-->
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

<!--        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>-->

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

MainConfigOfProfile.java

package com.hutu.boot01.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * Profile:
 * Spring为我们提供的可以根据当前的环境,动态的激活和切换一系列组件的功能;
 * 开发环境,测试环境,生产环境
 * 我们以切换数据源为例:
 * 数据源:开发环境中(用的是A数据库)、测试环境(用的是B数据库)、而生产环境(用的又是C数据库)
 */
@Configuration
@PropertySource("classpath:/dbconfig.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("db.user")
    private String user;

    private StringValueResolver valueResolver;

    private String driver;

    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");

        source.setDriverClass(driver);
        return source;
    }

    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");
        source.setDriverClass(driver);
        return source;
    }

    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");
        source.setDriverClass(driver);
        return source;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        driver = valueResolver.resolveStringValue("${db.driverClass}");
    }
}

src/resources/dbconfig.properties

db.user=root
db.password=root
db.driverClass=com.mysql.cj.jdbc.Driver

测试

@Test
public void test_db() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);

    System.out.println("===============");
    String[] names = context.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
    System.out.println("===============");
    context.close();
}

结果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfProfile
testDataSource
devDataSource
prodDataSource

总结: 三种获取配置文件中的值

  1. 直接通过属性上面加上@Value("${db.user}")

  2. 在参数上面使用@Value("${db.password}") public DataSource dataSourceTest(@Value("${db.password}") String pwd)

  3. 实现EmbeddedValueResolverAware接口,在setEmbeddedValueResolver(StringValueResolver resolver)方法里面进行获取:里面使用 resolver.resolveStringValue("${db.driverClass}")方法解析,返回赋值给成员属性private StringValueResolver resolver;


5.6. @Profile根据环境注册bean

@Profile: Spring为我们提供的可以根据当前的环境,动态的激活和切换一系列组件的功能; 开发环境,测试环境,生产环境

以切换数据源为例: 数据源:开发环境中(用的是A数据库)、测试环境(用的是B数据库)、而生产环境(用的又是C数据库)

@Profile: 指定组件在哪一个环境的情况下才能被注册到容器中,不指定任何环境都能被注册这个组件 1)加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境,如果指定了default,那么这个bean默认会被注册到容器中 2)@Profile 写在配置类上,只有是指定的环境,整个配置类里面的所有配置才能开始生效 3)没有标注环境标识的bean,在任何环境都是加载的

现在,我来用@Profile注解只激活哪一个数据源:

加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。

在每个方法上面添加了@Profile注解

package com.hutu.boot01.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * Profile:
 * Spring为我们提供的可以根据当前的环境,动态的激活和切换一系列组件的功能;
 * 开发环境,测试环境,生产环境
 * 以切换数据源为例:
 * 数据源:开发环境中(用的是A数据库)、测试环境(用的是B数据库)、而生产环境(用的又是C数据库)
 */
@Configuration
@PropertySource("classpath:/dbconfig.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("db.user")
    private String user;

    private StringValueResolver valueResolver;

    private String driver;

    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");

        source.setDriverClass(driver);
        return source;
    }

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");
        source.setDriverClass(driver);
        return source;
    }

    @Profile("prod")
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource source = new ComboPooledDataSource();
        source.setUser(user);
        source.setPassword(pwd);
        source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");
        source.setDriverClass(driver);
        return source;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        driver = valueResolver.resolveStringValue("${db.driverClass}");
    }
}

测试

@Test
public void test_db() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);

    System.out.println("===============");
    String[] names = context.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
    System.out.println("===============");
    context.close();
}

结果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfProfile

数据源一个都没有打印出来。在dataSourceTest方法上添加默认值@Profile("default")。

@Profile("default")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}") String pwd) throws PropertyVetoException {
    ComboPooledDataSource source = new ComboPooledDataSource();
    source.setUser(user);
    source.setPassword(pwd);
    source.setJdbcUrl("jdbc:mysql://localhost:3306/guigu-auth?characterEncoding=utf-8&useSSL=false");

    source.setDriverClass(driver);
    return source;
}

结果

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfigOfProfile
testDataSource

使用命令行动态参数的方式:在虚拟机参数的位置加载-Dspring.profile.active=test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/283636.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023最新租号平台系统源码支持单独租用或合租使用

这是一款租号平台源码&#xff0c;采用常见的租号模式。目前网络上还很少见到此类类型的源码。 平台的主要功能如下&#xff1a; 支持单独租用或采用合租模式&#xff1b; 采用易支付通用接口进行支付&#xff1b; 添加邀请返利功能&#xff0c;以便站长更好地推广&#xf…

基于蚁狮算法优化的Elman神经网络数据预测 - 附代码

基于蚁狮算法优化的Elman神经网络数据预测 - 附代码 文章目录 基于蚁狮算法优化的Elman神经网络数据预测 - 附代码1.Elman 神经网络结构2.Elman 神经用络学习过程3.电力负荷预测概述3.1 模型建立 4.基于蚁狮优化的Elman网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

逻辑卷学习后续----------缩容

一、缩容&#xff1a;缩减大小 ext4可以 &#xff0c; xfs无法缩减&#xff0c;缩减会影响业务 1.解挂载 2.检查文件系统完整性 3.缩减文件系统 4.缩减逻辑卷上下一致 5.再挂载回去 添加磁盘 文件系统只能装ext4 缩减文件系统 resize2fs 挂载失败需要重新安装文件系统…

磁盘阵列(RAID)

1.独立硬盘冗余阵列&#xff08;RAID, Redundant Array of Independent Disks&#xff09; 旧称廉价磁盘冗余阵列&#xff08;Redundant Array of Inexpensive Disks&#xff09;&#xff0c;简称磁盘阵列 用虚拟化存储技术把多个硬盘组合起来&#xff0c;成为一个或多个硬盘阵…

[C#]使用ONNXRuntime部署一种用于边缘检测的轻量级密集卷积神经网络LDC

源码地址&#xff1a; github.com/xavysp/LDC LDC: Lightweight Dense CNN for Edge Detection算法介绍&#xff1a; 由于深度学习方法的快速发展&#xff0c;近年来&#xff0c;用于执行图像边缘检测的卷积神经网络&#xff08;CNN&#xff09;模型爆炸性地传播。但边缘检测…

Selenium教程04:鼠标+键盘网页的模拟操作

在webdriver 中&#xff0c;鼠标操作都封装在ActionChains类中&#xff0c;使用的时候需要导入这个包。 from selenium.webdriver import ActionChainsActionChains方法列表如下&#xff1a; click(on_elementNone) ——单击鼠标左键click_and_hold(on_elementNone) ——点击…

开始使用MEVN技术栈开发02 MongoDB介绍

开始使用MEVN技术栈开发02 MongoDB介绍 MongoDB介绍 As indicated by the ‘ M ’ in MEVN, we will use MongoDB as the backend database for our app. MongoDB is a NoSQL database. Before we talk about what is a NoSQL database, let ’ s first talk about relationa…

[每周一更]-(第48期):一名成熟Go开发需储备的知识点(问题篇)- 1

问题篇 1、Go语言基础知识 什么是Go语言&#xff1f;它有哪些特点&#xff1f;Go语言的数据类型有哪些&#xff1f;Goroutine是什么&#xff1f;它与线程的区别是什么&#xff1f;介绍一下Go语言的垃圾回收机制。 2、并发和并行 什么是并发和并行&#xff1f;它们之间的区别…

Java超高精度无线定位技术--UWB (超宽带)人员定位系统源码

UWB室内定位技术是一种全新的、与传统通信技术有极大差异的通信新技术。它不需要使用传统通信体制中的载波&#xff0c;而是通过发送和接收具有纳秒或纳秒级以下的极窄脉冲来传输数据&#xff0c;从而具有GHz量级的带宽。 UWB&#xff08;超宽带&#xff09;高精度定位系统是一…

Java方法(定义和调用,带参数方法定义和调用,带返回值方法的定义和调用,方法的注意事项,方法重载)

文章目录 1. 方法概述1.1 方法的概念 2. 方法的定义和调用2.1 无参数方法定义和调用2.3 无参数方法的练习 3. 带参数方法定义和调用3.1 带参数方法定义和调用3.2 形参和实参3.3 带参数方法练习 4. 带返回值方法的定义和调用4.1 带返回值方法定义和调用4.2 带返回值方法练习14.3…

React学习计划-React16--React基础(八)react-redux使用与优化,纯函数介绍

笔记gitee地址 学习了 redux,为什么还要讲react-redux呢&#xff1f; redux不是专门为react所创建的,只不过在某一刻&#xff0c;react和redux看对眼了&#xff0c;所以俩人走到了一起&#xff0c;所以为了更好的支持redux,react官方出了react-redux来更好的支持redux 1. react…

UntiyShader(七)Debug

目录 前言 一、利用假彩色图像 二、利用Visual Studio 三、帧调试器 前言 Debug&#xff08;调试&#xff09;&#xff0c;是程序员检查问题的一种方法&#xff0c;对于一个Shader调试更是一种噩梦&#xff0c;这也是Shader难写的原因之一——如果效果不对&#xff0c;我们…

JDBC->SpringJDBC->Mybatis封装JDBC

一、JDBC介绍 Java数据库连接&#xff0c;&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口&#xff0c;提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们…

Leetcode每日一题周汇总 (12.24-12.30)

Leetcode每日一题周汇总 (12.24-12.30) 1.Sunday (12.24) 题目链接&#xff1a;1954. 收集足够苹果的最小花园周长 - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你一个用无限二维网格表示的花园&#xff0c;每一个 整数坐标处都有一棵苹果树。整数坐标…

今晚咱们一起来场特别的技术跨年!!

▼最近直播超级多&#xff0c;预约保你有收获 今晚跨年直播&#xff1a;《LLM在电商推荐系统的应用案例实战》 —1— 今晚咱们来场技术跨年&#xff01; LLM 大模型无疑是2023年最重磅的技术&#xff0c;逐渐在各行各业产生了越来越重要的实质影响&#xff0c;2024年的钟声今晚…

vue3-12

需求是用户如果登录了&#xff0c;可以访问主页&#xff0c;如果没有登录&#xff0c;则不能访问主页&#xff0c;随后跳转到登录界面&#xff0c;让用户登录 实现思路&#xff0c;在用户登录之前做一个检查&#xff0c;如果登录了&#xff0c;则token是存在的&#xff0c;则放…

Android Studio如何查找和替换

目录 前言 一、概述 二、总结 三、更多资源 前言 在Android Studio中&#xff0c;查找和替换是非常常见的操作&#xff0c;它可以帮助我们快速地定位和修改代码中的错误或不合适的内容。本文将介绍如何在Android Studio中进行查找和替换操作&#xff0c;包括基本的查找和替…

蓝牙音频发射模块 蓝牙耳机连接是如何操作的以BT321F为例

一、简介 蓝牙发射模块 蓝牙耳机连接是如何操作的以BT321F模块为例 因为蓝牙音频类的产品&#xff0c;基本上大体分为三类 第一类&#xff1a;蓝牙耳机&#xff0c;包括&#xff1a;tws无线耳机&#xff0c;如airpods&#xff0c;头戴耳机如bose qc35系列等等 第二类&#…

QtitanRibbon 开始使用实例

新建一个界面程序&#xff1a; 修改项目里面的源码&#xff1a; 至此&#xff0c;一个简单界面就出来了&#xff0c;效果如下所示&#xff1a;