Spring注解开发笔记001

-----------------------spring的注解开发:-------------------

一、组件的注册

注:

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
//注解方式上下文加载配置类MainConfig2.class

给容器中注册组件:

1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)【自己使用】

  1. @Bean【导入的第三方包里面的组件】

3)@Import【快速的给容器中导入一个组件】

​ 1)、@Import(要导入到容器中的组件)

​ 2)、ImportSelector:返回需要导入的组件的全类名数组。springBoot常用

​ 3)、ImportBeanDefinitionRegistrar:手动注册bean到容器中。

4)使用Spring提供的FactoryBean(工厂Bean);

​ 1)、默认获取到的是工厂bean调用getObject创建的对象

​ 2)、要获取工厂Bean本身,我们需要给id前面加一个&

​ @colorFactoryBean

1. 注册组件(@Bean)

  • config

    //配置类 == 配置文件
    @Configuration //告诉spring这是一个配置类
    public class MainConfig {
        //给容器注册一个bean;类型为返回值的类型,默认按类名访问
        @Bean("sdf")
        public Person person(){
            return new Person("lisi",20);
        }
    }
    
  • sdd

    package com.sdd;
    
    public class Person {
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        public Person() {
        }
    }
    
    
  • Test

      @Test
        public void demo1(){
    
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
            Person person1 = applicationContext.getBean(Person.class);
    
            System.out.println(person1);
        }
    
  • 运行结果

image.png

2. 包扫描(@ComponentScan和@ComponentScans)



注解方式:

 @ComponentScan(value = "com.it",includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class})
        },useDefaultFilters = false)
//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] 指定扫描的时候按照什么规则排除相应的组件
//includeFilters = Filter[] 指定扫描的时候按照什么规则包含相应的组件
    // FilterType.ANNOTATION :注解方式
    // FilterType.ASSIGNABLE_TYPE:按照给定的类型
    //FilterType.ASPECTJ :使用ASPECTJ表达式
    //FilterType.REGEX  :使用正则表达式
    //FilterType.CUSTOM :使用自定义规则
  • 使用ComponentScans可以实现多指定ComponentScan的规则
@ComponentScans(value = {//使用ComponentScans可以实现多指定ComponentScan的规则
        @ComponentScan(value = "com.it",includeFilters = {
                @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})
        },useDefaultFilters = false)
})
//注useDefaultFilters = false是指不自动扫描容器中的注解@Serivce、@Controller等
  • 使用自定义扫描规则必须实现TypeFilter接口
public class MyTypeFilter implements TypeFilter {
    /**
     *
     * @param metadataReader   读取到的当前正在扫描的类的信息
     * @param metadataReaderFactory :可以获取其他任何类的信息
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();


        String className = classMetadata.getClassName();
        System.out.println("---------->"+className);
        if (className.contains("er")){
            return true;
        }
        return false;
    }
}
  • 在包扫描中的应用:
@ComponentScans(value = {//使用ComponentScans可以实现多指定ComponentScan的规则
        @ComponentScan(value = "com.it",includeFilters = {
/*                @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class}),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {BookService.class},*/
                @ComponentScan.Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class})
        },useDefaultFilters = false)
})
public class MainConfig {
    //给容器注册一个bean;类型为返回值的类型,
    @Bean("person1")
    public Person person(){
        return new Person("lisi",20);
    }
}
  • 结果...
image.png

3. @Scope属性

     prototype:多实例  :ioc容器启动并不会去调用方法创建对象放在容器中。
                               第次获取的时候才会调用方法创建对象;
     singleton:单实例(默认值) ioc容器启动会调用方法创建对象放到ioc容器中
                               以后 每次获取直接从容器(map.get())中拿
     request:同一次请求创建一个实例
     session: 同一个session创建一个实例
image.png

3.1 懒加载(@Lazy):

  • 单实例bean:默认在容器启动的时候创建对象
  • 懒加载:容器启动不创建对象。第一次使用(获取)Bean创建对象,并初始化。

MainConfig2类:

    @Lazy
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加Person......");
        return new Person("张三",25);
    }

测试:

    @Test
    public void demo3(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
        System.out.println("ioc容器创建完成......");
        Object person = applicationContext.getBean("person");
        Object person2 = applicationContext.getBean("person");
        
        System.out.println(person.equals(person2));
    }

结果:

image.png

4. @Conditional:按照一定的条件给容器中注册bean

@Conditional 可以加在method上,也可以加在class上。

4.1 加在method上,满足条件时就给容器注册bean

    /**
     * @Conditional({Condition数组})  :按照一定的条件进行判断,满足条件给容器中注册bean
     *  如果系统是windows,给容器中注册   bill
     *           linux ,             linus
     * @return
     */
//按照类型获取Bean中的所有信息
Map beansOfType = applicationContext.getBeansOfType(Person.class);
//获得系统的运行环境
Environment environment = applicationContext.getEnvironment();
//获得操作系统的名字
String property = environment.getProperty("os.name");

创建类型:

  • LinuxCondition
//判断是否为Linux系统
public class LinuxCondition implements Condition {
    /**
     *
     * @param context :判断条件能使用的上下文(环境)
     * @param metadata :注释信息
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //是否linux系统
        //1.能获取到ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();

        //2.获得类加载器
        ClassLoader classLoader = context.getClassLoader();

        //3.获得当前环境信息
        Environment environment = context.getEnvironment();

        //4.获得到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        String property = environment.getProperty("os.name");
        if (property.contains("linux")){
            return true;
        }
        return false;
    }
}
  • WindowsCondition
//判断是否为Windows系统
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        //获取环境配置信息
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Windows")){
            return true;
        }
        return false;
    }
}
  • 配置类:
    /**
     * @Conditional({Condition})  :按照一定的条件进行判断,满足条件给容器中注册bean
     *  如果系统是windows,给容器中注册 bill
     *           linux ,           linus
     * @return
     */
    @Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01(){
        System.out.println("给bill容器中添加Person");
        return new Person("Bill Gates",62);
    }

    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person02(){
        System.out.println("给linus容器中添加Person");
        return new Person("Linus",50);
    }
  • 测试
@Test
public void demo04(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] names = applicationContext.getBeanNamesForType(Person.class);

    Map beansOfType = applicationContext.getBeansOfType(Person.class);


    Environment environment = applicationContext.getEnvironment();

    //动态获取环境变量的值   windows 10
    String property = environment.getProperty("os.name");
    System.out.println(property);
    for (String name : names) {
        System.out.println(name);
    }
    System.out.println("*************");
    System.out.println(beansOfType);

}
  • 结果:
image.png

4.2 加在class上,满足当前条件,这个类中配置的所有bean注册才能生效

  • MainConfig2(若满足WindowsCondition,则就创建 bill和**linus ** bean)
@Conditional(WindowsCondition.class)
@Configuration  //告诉spring这是一个配置类
public class MainConfig2 {

    /**
     * @Conditional({Condition})  :按照一定的条件进行判断,满足条件给容器中注册bean
     *  如果系统是windows,给容器中注册 bill
     *           linux ,           linus
     * @return
     */

    @Bean("bill")
    public Person person01(){
        System.out.println("给bill容器中添加Person");
        return new Person("Bill Gates",62);
    }

//    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person02(){
        System.out.println("给linus容器中添加Person");
        return new Person("Linus",50);
    }
}
  • Test
image.png

5. 打印容器中的所有组件

    //打印容器中的所有组件
    private void print(AnnotationConfigApplicationContext applicationContext){
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }

6. @Import -给容器中快速导入一个组件

  • 单个组件:容器会自动注册组件。
image.png

​ 就成功导入到组件中了。

  • 多个组件

6.1 @Import[要导入到容器中的组件]

6.2 ImportSelector:返回需要导入的组件的全类名数组(spring-Boot最常用的)

//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    //返回值,就是到导入到容器中的组件全类名
    //AnnotationMetadata :当前标注@Import注解的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {

//        importingClassMetadata.
        //必须是全类名的形式。注意
        return new String[]{"com.it.bean.Blue","com.it.bean.Yellow"};
    }
}
  • 使用
  • 测试

6.3 ImportBeanDefinitionRegistrar:手动注册bean到容器中

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata  当前类的注解信息
     * @param registry                BeanDefinition注册类
     *              把所有需要添加到容器中的bean:
     *              BeanDefinitionRegistry.registerBeanDefinition:手工注册
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean definition = registry.containsBeanDefinition("com.it.bean.Red");
        boolean definition1 = registry.containsBeanDefinition("com.it.bean.Dd");
        
        if (definition && definition1) {
            RootBeanDefinition BeanDefinition = new RootBeanDefinition(RainBow.class);
            //指定别名
            registry.registerBeanDefinition("rainBow",BeanDefinition);
        }
    }
}

7. FactoryBean注册组件(spring提供的也叫工厂Bean)

    1. 默认获取的是工厂bean调用getObject创建对象
    1. 要获取工厂Bean本身,我们需要给id前面加一个&
  • 例子
//创建一个spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean {
    //返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean.....getObject....");
        return new Color();
    }

    @Override
    public Class getObjectType() {
        return Color.class;
    }

    //是单例?
    //true,这个bean是个单实例,在容器中保存一份
    //false,多实例,每次获取都会创建一个新实例
    @Override
    public boolean isSingleton() {
        return false;
    }
}
  • 测试一下
@Test
public void ImportTest(){
    
    //工厂Bean获取的是调用getObject创建的对象
    //多实例的Bean每创建一次对象就调用一次getObject()方法
    Object bean1 = applicationContext.getBean("colorFactoryBean");
    Object bean2 = applicationContext.getBean("colorFactoryBean");
    System.out.println("bean1的类型是:"+bean1.getClass());
    System.out.println(bean1 == bean2);
    System.out.println("***********************");
    //加上“&”获取的就是获取工厂本身
    Object bean3 = applicationContext.getBean("&colorFactoryBean");
    System.out.println(bean3);
}

二、生命周期

1.@Bean指定初始化和销毁方法

1)、指定初始化和销毁方法:

  • 通过@Bean指定init-method和destroy-method方法
  • Car
public class Car {

    public Car(){
        System.out.println("car constructor..");
    }
    public void init(){
        System.out.println("car ....init...");
    }
    public void detory(){
        System.out.println("car ....detory...");
    }
}
  • 配置类
/**
 * bean的生命周期:
 *      bean创建----初始化---销毁的过程
 * 容器管理bean的生命周期:
 * 我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们定义的初始化和销毁方法
 *
 * 构造(对象创建时)
 *          单实例:在容器启动的时候创建对象
 *          多实例:在每次获取的时候创建对象
 * 初始化:
 *        对象创建完成,并赋值好,调用初始化方法。。。。
 * 销毁:
 *        单实例:对象关闭后,调用销毁方法。。。
 *        多实例:容器不会管理这个bean;容器不会调用销毁方法
 *
 *  
 */
@Configuration
public class MainConfigOfLifeCycle {

//    @Scope("prototype")
    @Bean(initMethod = "init",destroyMethod = "detory")
    public Car car(){
        return new Car();
    }
}
  • 测试类
@Test
public void test01(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成...");

    applicationContext.getBean("car");

    //关闭容器
    applicationContext.close();
}
  • 单实例的bean(默认为单实例)
  • 多实例的bean(prototype)

2)、通过让Bean实现InitializingBean(定义初始化逻辑)

​ DisposableBean(定义销毁逻辑)

  • 配置类
@ComponentScan(value = "com.it.bean") //组件扫描的方式 
@Configuration
public class MainConfigOfLifeCycle {

//    @Scope("prototype")
    @Bean(initMethod = "init",destroyMethod = "detory")
    public Car car(){
        return new Car();
    }
}
  • 组件类
@Component //组件
public class Cat implements InitializingBean, DisposableBean {

    public Cat(){
        System.out.println("cat constructor....");
    }

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

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat...afterPropertiesSet...");
    }
}
  • 测试一下
@Test
    public void test01(){

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

//        applicationContext.getBean("car");

        //关闭容器
        applicationContext.close();
    }
  • 结果

3)、可以使用JSR250:

​ @PostConstruct:在bean创建完成并且属性赋值完成 ;来执行初始化

​ @PreDestroy:在容器销毁bean之前通知 我们进行清理工作

  • 组件
@Component
public class Dog {

    public Dog(){
        System.out.println("dog..constructor...");
    }

    //对象创建并赋值之后调用
    @PostConstruct
    public void init(){
        System.out.println("Dog ......@PostConstruct....");
    }
    //容器移除对象之前
    @PreDestroy
    public void destroy(){
        System.out.println("Dog ......@PreDestroy....");
    }
}
  • 测试
@Test
    public void test01(){

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

//        applicationContext.getBean("car");

        //关闭容器
        applicationContext.close();
    }
  • 结果

4)、BeanPostProcessor【interface】:bean的后置处理器:

​ 在bean初始化前后进行一些处理工作:

​ postProcessBeforeInitialization:在初始化之前工作

​ postProcessAfterInitialization:在初始化之后工作

  • 作用域:

    BeanPostProcessor.postProcessBeforeInitialization:在初始化之前

    初始化:

    BeanPostProcessor.postProcessAfterInitialization:在初始化之后

    销毁:

  • 组件:

/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization"+beanName+"=>"+bean);
        return bean;

    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization"+beanName+"=>"+bean);
        return bean;
    }
}
  • 测试:
    @Test
    public void test01(){

        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");

//        applicationContext.getBean("car");

        //关闭容器
        applicationContext.close();
    }
  • 结果:
遍历得到容器中所有的BeanPostProcessor:挨个执行beforeInitialization,
一但返回null,跳出for循环,不会执行后边的BeanPostProcessor.postProcessorsBeforeInitialization

BeanPostProcessor原理

populateBean(beanName, mbd, instanceWrapper);//给bean进行属性赋值的
initializeBean
{
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    invokeInitMethods(beanName, wrappedBean, mbd);//执行自定义初始化方法
    applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

Spring底层对BeanPostProcessor的使用:

  • bean赋值,注入其他组件,@AutoWired,生命周期注解功能,@Async,xxx BeanPostProcessor;

三、属性赋值

1、@Value赋值

1). 基本数值
2). 可以使用SpEL:#{}
3). 可以写${},取出配置文件【properties】中的值(在运行环境变量里面的值)
注:对于idea来说,它的路径resourse默认到文件,所以只需要文件名就只可以获取到里面的值

public class Person {
    
    //1.基本数值
    @Value("张三")
    private String name;
    //2.SpEL:#{}
    @Value("#{18-2}")
    private Integer age;
    //取出配置文件properties中的值
    @Value("${person.nickName}")
    private String nickName;

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", nickName='" + nickName + '\'' +
                '}';
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }
}
  • 注册组件
//使用@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中
//   加载完外部的配置文件以后使用${}取出配置文件的值
@PropertySource(value = {"person.properties"})
@Configuration  //声明配置类
public class MainConfigOfProperty {

    @Bean//注册一个组件
    public Person person(){
        return new Person();
    }
}
  • 测试类
//测试方法
public class IocTestPropertyValue {
    @Test
    public void test01(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProperty.class);


        printBean(applicationContext);

        System.out.println("-------------------------");

        Person person = (Person)applicationContext.getBean("person");
        System.out.println(person);

        //运行时的环境变量
        
        //这是第二种获得配置文件中的值的方式
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.nickName");
        System.out.println(property);

        //关闭容器
        applicationContext.close();
    }

    private void printBean(AnnotationConfigApplicationContext applicationContext){
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}
  • 结果

四、自动装配

/**
 *       自动装配:
 *        Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值;
 *      1) Autowired 自动注入
 *           2)、默认优先按照类型去容器中找相应的组件:applicationContext.getBean(BookDao.class);找到就   *            赋值
 *           2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找:
 *                              applicationContext.getBean("bookDao")
 *           3)、@Qualifier("bookDao2"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 *           4)、自动装配默认一定要将属性赋值好,没有就会报错;
 *              可以使用:@Autowired(required = false)
 *           5)@Primary:让spring自动装配的时候,默认使用首选Bean
 *                也可以继续使用@Qualifier指定需要装配的bean的名字
 *          BookService{
 *              @Autowired
 *             BookDao  bookDao
 *          }
 *       2)、Spring还支持使用@Resource(JSR250)和@Inject(JSR330)【java规范的注解】
            1)、@Resource:
                可以和@Autowired实现自动装配功能;默认是按组件名称进行装配的
                没有能支持@Primary功能没有支持@Autowired(required = false)
            2)、@Inject:
                需要导入javax.inject的包,和@Autowired的功能一样。没有required =        false的功能。
            @AutoWired:Spring定义的; 
            @Resource、@Inject都java规范
         
            AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能;
        3)、@Autowired:构造器、参数、方法、属性;都是从容器中获取参数组件的值
            1)、【标注在方法上】:@Bea+方法参数:参数从容器中获取;默认不写@Autowired           效果是一样的,都能自动装配。
                @Autowired //标注在方法:Spring容器创建当前对象,就会调用方法,完成                 赋值
                //方法使用的参数,自定义类型的值从ioc容器中获取
                public void setCar(Car car) {
                    this.car = car;
                }
            2)、【标注在构造器上】:如果组件只有一个有参构造器,这个有参构造器的                 @Autowired可以省略,参数位置的组件还是可以自动从容器中获取的
                @Autowired
                public Boss(Car car){
                
                }
            3)、【标注在参数上】:
                 public Boss(@Autowired Car car){
                 
                 }
                 
             4)、自定义的组件想要使用Spring容器底层的一些组件                               (Application,BeanFactory,xxx) 自定义组件实现xxxAware:在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
             把Spring底层一些组件注入到自定义的Bean中;
             xxxAware:功能使用xxxProcessor;
                    ApplicationContextAware-->ApplicationContextAwareProcessor;
             
 */
//配置类
@Configuration
@ComponentScan({"com.it.service","com.it.dao","com.it.controller"})
public class MainConfigOfAutowired {

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

}
  • Service
@Service
public class BookService {

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

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

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                '}';
    }
}
  • dao
//名字默认是类名字母小写
@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 + '\'' +
                '}';
    }
}
  • 测试
@Test
public void test01(){

    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowired.class);

    BookService bean = applicationContext.getBean(BookService.class);
    System.out.println(bean);
    
    //获得容器中的所有组件的名称
    String[] names = applicationContext.getBeanNamesForType(DataSource.class);
    for (String name : names) {
        System.out.println(name);
    }


    //关闭容器
    applicationContext.close();
}
  • 结果

1.自动装配,@Profile环境搭建

  • 配置类
/**
 * Profile
 *       Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的
 *
 *
*   开发环境、测试环境、生产环境:
 *   数据源:(/A)(/B)(/C);
 * @Profile
 */
@PropertySource(value = "dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("${db.user}")
    private String user;

    private StringValueResolver valueResolver;

    private String driverClass;

    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/book");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/bookk");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }
}
  • 测试
@Test
public void test01(){

    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext(MainConfigOfProfile.class);

    //获得容器中的所有组件的名称
    String[] names = applicationContext.getBeanNamesForType(DataSource.class);
    for (String name : names) {
        System.out.println(name);
    }

    applicationContext.close();
}
  • 配置文件(dbconfig.properties)
db.user=root
db.password=
db.driverClass=com.mysql.jdbc.Driver
  • 结果

小知识:

  • idea中如何切换运行环境:

2.实现自动装配@Profile

@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定任何环境下注册这个组件

1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境
2)、写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置类才能开始生效
3)、没有标注环境标识的bean在,任何环境下都是加载的;
    @Profile
  • 配置类
//@Profile("test")
@PropertySource(value = "dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("${db.user}")
    private String user;

    private StringValueResolver valueResolver;

    private String driverClass;


    @Bean
    public Yellow yellow(){
        return new Yellow();
    }
    @Profile("test")
    @Bean("testDataSource")
    public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/test");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Profile("dev")
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/book");
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Profile("prod")
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws  Exception{
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:/3306/bookk");

        dataSource.setDriverClass(driverClass);
        return dataSource;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        driverClass = valueResolver.resolveStringValue("${db.driverClass}");
    }
}
  • 测试
//1.使用命令行动态参数:在虚拟机参数位置加上-Dspring.profiles.active=test
//2.代码方式激活某种环境:
@Test
public void test01(){

    //1.创建applicationContext
    AnnotationConfigApplicationContext applicationContext =
            new AnnotationConfigApplicationContext();
    //2.设置需要激活的环境   ,运行的是test环境
    applicationContext.getEnvironment().setActiveProfiles("test");
    //3.注册主配置类
    applicationContext.register(MainConfigOfProfile.class);
    //4.启动刷新容器
    applicationContext.refresh();

    //获得容器中的所有组件的名称
    String[] names = applicationContext.getBeanNamesForType(DataSource.class);
    for (String name : names) {
        System.out.println(name);
    }


    //没有标识是什么环境的Yellow不论在什么环境下都可以运行
    Yellow yellow = applicationContext.getBean(Yellow.class);
    System.out.println(yellow);
    applicationContext.close();
}
  • 结果

你可能感兴趣的:(Spring注解开发笔记001)