spring注解驱动开发(DI功能)

一.在bean中注入Spring底层的组件

如果自定义组件想要使用Spring容器底层的一些组件,那么只需要在bean对象中实现xxxAware接口,在创建对象的时候,会调用接口规定的方法注入相关组件

1.注入IOC容器(applicationContext)

如过一个bean对象,想要在其内部使用applicationContext(注入applicationContext),那么此bean对象可以通过实现ApplicationContextAware接口,实例。

编写bean对象

package com.miracle.springAnnotation.bean;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

// 想要在bean中获取(注入)IOC容器,那么可以实现ApplicationContextAware接口
@Component
public class Person implements ApplicationContextAware {
    // 创建字段保存IOC容器
    private ApplicationContext  applicationContext;
    private String name;
    private Integer age;

    public Person() {

    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = 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 +
                '}';
    }

    // 复写接口方法
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 方法中会自动传入IOC容器,只需赋值给字段即可
        this.applicationContext = applicationContext;
    }

    public ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }
}

2.注入当前bean的名字

Spring创建一个bean对象,如果想把bean的id注入到bean对象中可以实现BeanNameAware接口,用法同上。

二.成员属性赋值(@Value)和加载外部配置文件(@PropertySource)

1.编写properties文件 person.properties

person.nickName=miracle

2.编写配置类MainConfig.java

package com.miracle.springAnnotation.config;

import com.miracle.springAnnotation.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

// 在配置类上添加 @PropertySource 注解 来加载properties文件,将k/v保存到环境变量中
// @PropertySource 注解 接收一个String数组,可以同时加载多个properties文件
// 参数形式:classpath:/com/myco/app.properties 或者 file:/path/to/file
@PropertySource(value = {"classpath:/person.properties"})
@Configuration
public class MainConfig {

    @Bean
    public Person person() {
        return new Person();
    }
}

3.编写bean对象 Person.java

package com.miracle.springAnnotation.bean;

import org.springframework.beans.factory.annotation.Value;

public class Person{

    // 使用@Value赋值,@Value注解里面可以接收的参数:
    // 1.基本数值
    // 2.可以写SPEL表达式: #{}的形式
    // 3.可以写${}:取出配置文件中(properties文件)的值(在运行环境变量里面的值)
    @Value("张三")
    private String name;
    @Value("#{20-2}")
    private Integer age;
    @Value("${person.nickName}")
    private String nickName;

    public Person() {

    }

    public String getNickName() {
        return nickName;
    }

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

    public Person(String name, Integer age) {
        this.name = name;
        this.age = 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 +
                ", nickName='" + nickName + '\'' +
                '}';
    }
}

4.测试

Person person = (Person) applicationContext.getBean("person");
System.out.println(person);
// 配置类加载properties文件后,可以在IOC容器中取出properties中的值
String value = applicationContext.getEnvironment().getProperty("person.nickName");
System.out.println(value);

output:
Person{name='张三', age=18, nickName='miracle'}
miracle

三.自动装配

1.@Autowired

功能:自动注入
(1)默认优先按照类型去容器中找对应的组件
(2)如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
(3)@Autowired可以接收参数@Autowired(required=false),那么@Autowired在容器中找不到相同类型的bean对象来注入时,不会报错
(4)当注解 @Autowired 和 @Qualifier 同时使用可通过id指定要装配的bean,用法

@Qualifier("beanID")
@Autowired 

@Autowired 不仅仅可以标注在成员属性上,还可以标注在构造器,方法,参数上
spring注解驱动开发(DI功能)_第1张图片

@Autowired标注在方法上的示例

创建bean对象 Boss.java
Boss需要Car对象

package com.miracle.springAnnotation.bean;

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

@Component
public class Boss {

    private Car car;

    public Car getCar() {
        return car;
    }

    // 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值
    // 方法使用的参数,自定义类型的值从ioc容器中获取(这里的参数是 Car car,Spring就会从容器中找Car类型赋值)
    @Autowired
    public void setCar(Car car) {
        this.car = car;
    }

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

创建bean对象 Car.java

package com.miracle.springAnnotation.bean;

import org.springframework.stereotype.Component;

@Component
public class Car {

}

@Autowired标注在构造方法上的示例

package com.miracle.springAnnotation.bean;

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

// @Component注解在向ioc容器中添加组件的时候,
// Spring容器默认会调用无参构造器创建对象,再进行初始化赋值等操作
@Component
public class Boss {

    private Car car;

    // 构造器的Car car 参数会从容器中获取
    @Autowired
    public Boss(Car car) {
        System.out.println("Boss有参构造器");
        this.car = car;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

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

@Autowired标注在参数上的示例

同上

2.@Primary

package com.miracle.springAnnotation.config;

import com.miracle.springAnnotation.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;

@ComponentScan(value = {"com.miracle"})
@Configuration
public class MainConfig2 {

    // @Primary注解将bookDao设置成容器中首选bean,
    // 当其他bean要注入bookDao时,如果容器中有多个bean的类型是bookDao
    // 那么使用@Autowired注解注入(不能再用@Qualifier)时,优先注入@Primary注解修饰的bean
    @Primary
    @Bean
    public BookDao bookDao() {
        return new BookDao();
    }
}

3.@Resource

这个注解是java规范的,和前面几个注解不兼容
(1)@Resource注解加到字段上和 @Autowired 注解效果相同
(2)@Resource注解还可以指定beanID

@Resource(name="beanID")

4.@Profile

@Profile 注解 是 Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能
例如:开发时,有开发环境,测试环境,生产环境
以数据源为例:有开发库,测试库,生产库,想实现动态切换

下面已配置项目数据源为例:
(1)数据库配置文件:dbconfig.properties

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

(2)配置类:MainConfig4.java

package com.miracle.springAnnotation.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
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 javax.sql.DataSource;
import java.beans.PropertyVetoException;

/**
 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定(不加@Profile注解),任何环境下都能注册这个组件
 * 加了环境标识(@Profile)的bean,只有这个环境被激活的时候才能注册到容器中
 * 另外标注了@Profile("default)的bean会被激活
 * 此外@Profile 还可以写在配置类上,只有是指定的环境的时候,整个配置类里面的所有所有配置才能生效
 */
// 加载数据库配置文件
@PropertySource(value = {"classpath:/dbconfig.properties"})
@Configuration
public class MainConfig4 {

    // 获取数据库配置文件中参数的第一种方式
    @Value("${db.user}")
    private String user;

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

    @Profile("test")
    // 向容器中添加数据源(测试数据源)
    @Bean("testDataSource")                          // 获取数据库配置文件中参数的第二种方式
    public DataSource dataSourceTest(@Value("${db.password}") String password) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 设置数据源信息
        dataSource.setDriverClass(driverClass);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jing_dong");
        dataSource.setUser(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Profile("dev")
    // 向容器中添加数据源(开发数据源)
    @Bean("devDataSource")
    public DataSource dataSourceDev(@Value("${db.password}") String password) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 设置数据源信息
        dataSource.setDriverClass(driverClass);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test2");
        dataSource.setUser(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Profile("prod")
    // 向容器中添加数据源(生产数据源)
    @Bean("prodDataSource")
    public DataSource dataSourceProd(@Value("${db.password}") String password)throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        // 设置数据源信息
        dataSource.setDriverClass(driverClass);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test1");
        dataSource.setUser(user);
        dataSource.setPassword(password);
        return dataSource;
    }
}

(3)激活指定环境:
方式一:
指定虚拟机参数的方式
启动java程序时,追加参数

-Dspring.profiles.active=test,dev

方式二:
创建IOC容器的时候指定哪个环境

// 创建无参的AnnotationConfigApplicationContext 对象
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 设置需要激活的环境 可以同时设置多个环境,这里设置 test和dev
applicationContext.getEnvironment().setActiveProfiles("test", "dev");
// 注册主配置类
applicationContext.register(MainConfig4.class);
// 启动刷新容器
applicationContext.refresh();

你可能感兴趣的:(spring)