Spring5框架入门学习之常见注解配置(三)

Spring除了提供基于xml配置还提供了基于注解的配置,开发中经常用基于注解的方式。Spring提供了很多注解掌握其使用方法与实现原理是非常有必要的。

@Required

最新Spring5中该注解标记为过时的,此注解应用于JavaBean的setter方法上。

@Deprecated
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Required {
}

这个注解表明Bean设置属性的时候必须装配明确的属性值,下面演示其用法。

  • 新增JavaBean
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class Student {
    private String name;
    private Integer age;
    private Grade grade;
    @Required
    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}


@Data
public class Grade {
    private String gradeLevel;
}
  • 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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="student" class="com.codegeek.day7.Student"/>
    <bean id="grade" class="com.codegeek.day7.Grade"/>
</beans>

我们在 StudentsetGrade 方法加入了注解,表明当容器初始化创建Student 类的时候必须也要初始化 Grade 类然后将 Grade 值注入 Student 类中,如果我们像上面那样编辑器会给我们一个错误提示:
在这里插入图片描述
然后我们对xml配置文件做以下改动:
在这里插入图片描述
然后发现编辑器不在告警。

@Autowired

相信大家对此注解一定不会陌生,在日常开发中最常见的使用场景就是:如果类A需要调用类B的方法,此时我们可以将类B做为类A的成员属性然后在这个成员属性加上此注解即可。

@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;
}

下面演示其用法 我们在Student 类注入 Grade 类。
在这里插入图片描述
然后为Grade类属性进行赋值:
在这里插入图片描述
运行测试类:
在这里插入图片描述

注入原理

在这里插入图片描述
当要注入 Grade 对象 @Autowired 注解首先会跟着类型去匹配IOC容器中类型为Grade 的类,找到就返回并设置否则返回 NoSuchBeanDefinitionException 异常。
如果有多个类型的Bean那么IOC容器会注入那个呢?让我们先定义两个同类型的Bean如下所示:
在这里插入图片描述
然后在跑一次测试的代码:我们发现注入的依然是idgrade 的那个 Bean 对象。
在这里插入图片描述
原因是:当发现多个类型的Bean对象的时候,Spring会以注入对象的变量名称做为 id 去IOC容器中匹配该id。在这里插入图片描述
若是找到就返回否则会报以下错误:
在这里插入图片描述
例如我们将变量名称改为 grade1 如下:

    @Autowired
    private Grade grade1;

然后我们运行以下测试类的代码就抛出异常如下所示:
在这里插入图片描述

@Qualifier

上面我们发现注入类类型有多个时,Spring容器会进行抛异常处理。我们可以指定id的类此时就要使用到 @Qualifier注解。
在这里插入图片描述
我们再次运行测试类我们发现grade2对象已经注入成功。
在这里插入图片描述

@Resource

Spring也支持JSR-250注解 @Resource默认情况下其也是根据类的成员变量名去IOC容器中查找类,如下我们使用 @Resource 注解 Spring容器会在IOC容器查找 idgrade1Grade,与上面类似找到就返回对象并注入否则还是抛出异常。

  @Resource
    private Grade grade1;

在这里插入图片描述
我们对注入对象进行如下修改:

  @Resource(name = "grade2")
    private Grade grade1;

然后Spring容器会在容器查找 idgrade2Grade 类对象。此时指定了 name 属性的 @Resource 等价与@Autowired@Qualifier 组合。
在这里插入图片描述

@Configuration @Bean

@Configuration 注解表明该类为配置类其功能相当于我们常常配置的xml数据源配置.
@Bean 声明一个受Spring管理的JavaBean对象其相当于我们xml配置中的<bean> 标签。我们定义以下配置类:

@Configuration
public class ApplicationConfiguration {

    @Bean(name = "student2")
    public Student createStudent() {
        return new Student("张三", 23);
    }
}

然后xml中配置可以扫描此注解的功能:
在这里插入图片描述
跑一下测试的代码如下:
在这里插入图片描述

@Primary

一般按照如下根据类型获取Bean会获取多个类型时,此时可以对某个Bean设置 @Primary 这样Spring优先返回指定了此注解的Bean。
在这里插入图片描述
我们对配置类进行如下更改:
在这里插入图片描述
然后我们在跑一下测试类的代码:
在这里插入图片描述
我们发现Spring容器优先返回了加 @Primary 的Bean对象。

类路径扫描注解@Component及其同义注解

相信开发人员对 @Service @Controller @Repository 已经很熟悉了,我们都知道其分别对应着服务层、表现层、持久层而 @Component 属于Spring管理组件的通用注解。通过查看源码我们可以看到其他三个注解都是构建在 @Component 之上
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开发中如果想要Spring可以自动检测加了注解的类并注入其相应的Bean,需要我们加入 @ComponentScan
在这里插入图片描述
也可以通过xml配置 <context:component-scan> ,两者效果是一致的。
在这里插入图片描述

@Import

与我们常常在某个Xml中 import 其他模块xml配置一样,我们也可以使用某个配置类import 其他配置类正向下面这样。

  • xml中导入其他配置xml信息
    在这里插入图片描述
  • 配置类导入其他配置类
@Configuration
public class DataConfiguration {
    @Bean
    public Grade createGrade() {
        return new Grade("大学一年级");
    }
}

在这里插入图片描述

@ImportResource

我们在xml配置了一个id为 grade2Grade 类如下所示:
在这里插入图片描述
然后我们使用 AnnotationConfigApplicationContext 这个类去获取上面Grade类代码如下所示:

    @Test
    public void testRequired() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(ApplicationConfiguration.class);
        annotationConfigApplicationContext.refresh();
        Grade bean = annotationConfigApplicationContext.getBean("grade2", Grade.class);
        System.out.println("\n" + bean);
    }

运行确报错 No bean named 'grade2' available 的异常。
在这里插入图片描述
出现这个原因是我们的 ApplicationConfiguration 这个类没有配置名称为grande2 的对象但我们的xml配置文件已经定义了该Bean,此时我们可以使用@ImportResource 将配置文件内容加入到 ApplicationConfiguration 这个类中解决问题。
在这里插入图片描述

@Profile

在开发中经常有这样的需求:不同开发环境下注册不同的Bean对象以方便我们在不同环境下完成不同的业务逻辑如:开发环境、测试环境、生产环境等。此时我们可借助@Profile帮助我们在不同的环境注册不同的Bean,下面以一个简单的案例演示其使用。

  • 新增三个不同环境配置类
@Configuration
@Profile(value = "dev")
public class DevConfiguration {

    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://localhost/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}


@Configuration
@Profile(value = "prop")
public class PropConfiguration {
    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://10.211.55.1/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}


@Configuration
@Profile(value = "qa")
public class QAConfiguration {

    @Bean(name = "dataSource")
    public DataSource createDataSource(@Qualifier("dataConfig") DataConfig config) throws SQLException {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setDriver(config.getDriver());
        dataSource.setUsername(config.getUserName());
        dataSource.setPassword(config.getPassword());
        return dataSource;
    }

    @Bean(name = "dataConfig")
    public DataConfig devData() throws SQLException {
        String url = "jdbc:mysql://10.211.55.5/test?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8&autoReconnect=true";
        Driver driver = new Driver();
        String userName = "root";
        String password = "123456";
        return new DataConfig(driver, url, userName, password);
    }
}

在这里插入图片描述

@PropertySource

Spring中有个接口Environment,它对应用环境建立了一个Profile 与<kbdProperty 两个概念。我们可以设置额外的Properties文件并将其加入到Spring配置文件中,如下是一个简单的使用案例:

  • 新增JavaBean对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeployConfiguration {

    private String deployUrl;
    private String deployUser;
    private String deployPath;
    private String deployEnvironment;
}

@Configuration
@PropertySource(value = "classpath:day7/customize.properties")
public class PropertySourceConfiguration {

    @Autowired
    private Environment environment;

    @Bean(name = "deployConfiguration")
    public DeployConfiguration create() {
        DeployConfiguration configuration = new DeployConfiguration();
        configuration.setDeployEnvironment(environment.getProperty("deploy.environment"));
        configuration.setDeployPath(environment.getProperty("deploy.path"));
        configuration.setDeployUrl(environment.getProperty("deploy.url"));
        configuration.setDeployUser(environment.getProperty("deploy.user"));
        return configuration;
    }
}

  • 新增 customize.properties
deploy.environment=linux
deploy.path=/soft/service/spring-tomcat
deploy.user=codegeekgao
deploy.url=10.211.55.1

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章