一.spring-core IoC container(2) 基于annotation的配置方式

本文介绍了Spring框架中基于注解的Bean配置方法,包括@Autowired、@Required、@Resource等注解的使用,以及@Primary、@Qualifier如何限定自动装配选项。此外还探讨了@Component、@Service、@Controller等注解在类路径扫描下的组件管理和自动注册。
   上节阐述了spring bean 基于xml的配置及其他的bean概述,本届阐述spring基于annotation的方式配置Bean。在这里要说明的是,基于annotation的配置会优先于xml配置方式,所以,对于同一个bean,后续的xml配置会覆盖前面的annotation的配置。

一般可以通过下面的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">

    <context:annotation-config/>

</beans>
<context:annotation-config/>配置会隐式向spring容器注入AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor 这四个BeanPostProcessor,这四个BeanPostProcessor的作用让系统能够识别相应的注解

常用注解说明

@Required
常用于Bean中属性的setter上

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}

这个注解表示被注解的属性需要配置的期间被填充,可以通过在bean中明确的赋值,或者自动装配。如果没有,容器则会抛出异常。

@Autowired

@Autowired可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。
注意:@Autowired是根据类型(byType)进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier使用;
@Autowired 可以使用构造方法上,也可以在传统的setter方法上
在构造上使用:
public class MovieRecommender {
    private final CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}
在4.3以后,目标Bean中只有一个构造方法,那么可以省略这个注解,如果有多个构造方法,则至少要有一个构造方法要使用@Autowired 注解

在setter上使用:
public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}
还可以将注释应用于具有任意名称和/或多个参数的方法:
public class MovieRecommender {
    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}
可以用@autowired在属性上注解
public class MovieRecommender {
    private final CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    private MovieCatalog movieCatalog;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
   // ...
}

由于@Autowired 是基于类(byType)实现自动装配的,如果在容器中有多个类,可能会导致程序出错。这使得我们需要自动装备进行更加进一步的限制:
@Primary
这个注解表示如果自动装备的Bean存在有多个候选者,那么这个候选者将会成为自动装配的Bean

javacode-conf:
@Configuration
public class MovieConfiguration {
    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }
    @Bean
    public MovieCatalog secondMovieCatalog() { ... }
    // ...
}
xml-conf:
   ......
    <context:annotation-config/>
    <bean class="example.SimpleMovieCatalog" primary="true">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>
    ......

@Qualifier(“main”)
@Autowired配合@Qualifier("main") 可以实现根据名字进行自动装备,上述代码会装备上具有<qualifier value="main"/> 的Bean。

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

@Qualifier() 也可以作为构造或者方法的参数进行使用

@Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }

这只是@Qualifier() 的最基本用法,更详细的构造@Qualifier() 接口等可以看官方文档说明。

@Resource
使用@Resource 可以实现Bean自动装配时,通过byName 注入。

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

如果在@Resource 中没带任何参数,则会使用默认的name,这个name与你定义的类对象名称保持一致

public class SimpleMovieLister {
    //在此使用@Resource 则会自动装配name="first" 的bean
    private MovieFinder first;
    //在此使用@Resource 则会自动装配name="second" 的bean
    @Resource
    public void setMovieFinder(MovieFinder second) {
        this.movieFinder = movieFinder;
    }
}

需要说明的是,当没有多个同类型的Bean时,@autowired和@Resource 都是可以直接实现自动装配效果的
@PostConstruct and @PreDestroy

public class CachingMovieLister {
    //bean初始化之前
    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }
    //bean销毁之前
    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
}

使用类路径扫描和管理组件

在上述的注解使用过程中,Bean的初始化配置仍然在XML中,通过上述的注解只是通过解决类中的依赖关系的配置问题。这一部分通过扫描类路径检测出对应组件的方法,而这些组件又由类构成,这就使得我们可以不通过XML初始化Bean。先介绍几个注解

@Component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
@Repository 用于标注数据访问组件,即DAO组件
@Controller用于标注控制层组件(如struts中的action) 
@Service用于标注业务层组件 

其实下面的三个注解只是第一个注解的细化而已,通过细化可以实现spring自动的异常转换,并且在配合面向切面变成的工具使用更加方便

检测类和bean注册自动化

spring实现组件的自动检测和注册需要做如下的配置
基于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">
        //告诉spring需要扫描的包有哪些
    <context:component-scan base-package="org.example"/>
</beans>

基于javacode的配置:

@Configuration
@ComponentScan(basePackages = "org.example")
public class AppConfig  {
    ...
}

spring扫描的范围是通过类似过滤的方式可以自动配置的
这里写图片描述

@Configuration
@ComponentScan(basePackages = "org.example",
        includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),
        excludeFilters = @Filter(Repository.class))
public class AppConfig {
    ...
}
或者
<beans>
    <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>
这段配置表示忽略@Repository注解而使用.*Stub.*Repository 取代
使用components定义容器中的元数据

spring@Component 也可以像@Configuration 一样通过 @Bean 注解像容器中注入元数据

@Component
public class FactoryMethodComponent {
    @Bean
    @Qualifier("public")
    public TestBean publicInstance() {
        return new TestBean("publicInstance");
    }
    public void doWork() {
        // Component method implementation omitted
    }
}

基于annotation的配置方式的学习暂且到此为止,里面还有很多细节之处没有详细叙述,用到的时候仍需要参考文档

### 创建项目并托管到 Gitee 1. **创建 Java 项目**:使用 IDE(如 IntelliJ IDEA 或 Eclipse)创建个新的 Java 项目。以 IntelliJ IDEA 为例,选择 `File` -> `New` -> `Project`,选择 Java 项目类型,配置好 JDK 版本后完成创建。 2. **初始化 Git 仓库**:在项目根目录下打开终端,执行 `git init` 命令初始化本地 Git 仓库。 3. **添加远程仓库**:在 Gitee 上创建个新的仓库,复制仓库的 HTTPS 或 SSH 地址。在本地项目终端中执行 `git remote add origin <仓库地址>` 命令,将本地仓库与远程仓库关联。 4. **提交并推送代码**:执行 `git add .` 将所有文件添加到暂存区,接着执行 `git commit -m "Initial commit"` 提交更改,最后执行 `git push -u origin master`(若使用的是主分支)将代码推送到 Gitee 仓库。 ### 安装 MySQL 8 并创建数据库和表 1. **安装 MySQL 8**:从 MySQL 官方网站下载 MySQL 8 的安装包,按照安装向导完成安装。安装过程中设置好 root 用户的密码。 2. **创建数据库和表**:安装完成后,打开 MySQL 命令行客户端或使用可视化工具(如 Navicat)连接到 MySQL 服务器。执行以下 SQL 语句创建数据库 `test22` 和 `student` 表: ```sql -- 创建数据库 CREATE DATABASE test22; -- 使用数据库 USE test22; -- 创建 student 表 CREATE TABLE student ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, age INT ); ``` 3. **保存脚本到项目 DB 模块**:在项目中创建个 `DB` 模块(可以是个文件夹),将上述 SQL 脚本保存为 `.sql` 文件,如 `create_tables.sql`,并将该文件放入 `DB` 模块中。 ### 完成基于 XML 和 Annotation 配置IOC 容器 1. **添加依赖**:在项目的 `pom.xml`(如果是 Maven 项目)中添加 Spring 相关依赖: ```xml <dependencies> <!-- Spring Core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.18</version> </dependency> <!-- Spring Context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.18</version> </dependency> </dependencies> ``` 2. **基于 XML 配置IOC 容器**: - 创建个 Java 类,例如 `UserService`: ```java public class UserService { public void sayHello() { System.out.println("Hello from UserService!"); } } ``` - 创建个 `applicationContext.xml` 文件,配置 `UserService` 实例: ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.example.UserService"/> </beans> ``` - 在 Java 代码中加载 XML 配置文件并获取 `UserService` 实例: ```java import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.sayHello(); } } ``` 3. **基于 Annotation 配置IOC 容器**: - 启用注解支持,在 `applicationContext.xml` 中添加以下配置: ```xml <context:component-scan base-package="com.example"/> ``` - 在 `UserService` 类上添加 `@Service` 注解: ```java import org.springframework.stereotype.Service; @Service public class UserService { public void sayHello() { System.out.println("Hello from UserService!"); } } ``` - 修改 `Main` 类,使用注解方式获取 `UserService` 实例: ```java import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.sayHello(); } } ``` ### 用 Spring 创建线程池执行耗时任务 1. **添加 Spring 任务执行依赖**:在 `pom.xml` 中添加以下依赖: ```xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.3.18</version> </dependency> ``` 2. **配置线程池**:在 `applicationContext.xml` 中添加以下配置: ```xml <task:executor id="taskExecutor" pool-size="5"/> ``` 3. **创建耗时任务类**: ```java import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class TimeConsumingTaskService { @Async("taskExecutor") public void performTask() { try { // 模拟耗时操作 Thread.sleep(5000); System.out.println("Task completed!"); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` 4. **调用耗时任务**: ```java import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); TimeConsumingTaskService taskService = context.getBean(TimeConsumingTaskService.class); taskService.performTask(); System.out.println("Main thread continues..."); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值