本文最后更新于:4 个月前
spring-day02
第一章 基于注解管理bean
第一节 IOC的相关注解及包扫描
1. 注解的优势
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。使用注解开发比使用XML更加简洁明了
2. 包扫描
使用注解进行Bean管理必须要在xml配置文件中进行包扫描,这样的话spring-framework才能够解析你在Bean上所添加的注解,包扫描包含下面列举的四种情况:
2.1 最基本的扫描方式[常用]
扫描指定包下的所有类以及其子包下的所有类
1 2 3
|
<context:component-scan base-package="com.atguigu.ioc.component"/>
|
2.2 指定匹配模式
根据具体的匹配规则,扫描某个包下的某些类,需要注意规则匹配是匹配的直接在这个包下的类,不能是子包下的类
1 2 3 4
| <context:component-scan base-package="com.atguigu.ioc.component" resource-pattern="Soldier*.class"/>
|
2.3 指定要排除的组件
扫描某个包下的所有类,但是排除掉一些注解
1 2 3 4 5 6 7 8
| <context:component-scan base-package="com.atguigu.ioc.component"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
|
2.4 仅扫描指定组件
扫描某个包下的所有类,但是只扫描某种注解
1 2 3 4 5 6 7 8
|
<context:component-scan base-package="com.atguigu.ioc.component" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
|
3. 常用的进行IOC的注解
我们在类上添加注解,可以实现将该类的对象配置到spring的IOC容器中,常用的注解有如下四种:
3.1 Component注解
该注解主要用在普通类上,即除了三层结构之外的其它类的对象如果需要配置到spring的IOC容器中,那么则需要在类上添加Component注解
1 2 3 4 5
| package com.atguigu.ioc.component; import org.springframework.stereotype.Component; @Component public class CommonComponent { }
|
3.2 Controller注解
该注解主要用在控制层的类上,控制器处于三层结构中的表现层,在JavaWeb阶段表现层使用的是Servlet,而在学习了spring-framework之后,表现层我们使用Controller代替
1 2 3 4 5
| package com.atguigu.ioc.component; import org.springframework.stereotype.Controller; @Controller public class SoldierController { }
|
3.3 Service注解
该注解主要用在三层结构中的业务层的实现类上,用于将业务层的对象配置到spring的IOC容器中
1 2 3 4 5
| package com.atguigu.ioc.component; import org.springframework.stereotype.Service; @Service public class SoldierService implements ISoldierService{ }
|
3.4 Repository注解
该注解主要用在三层结构中的持久层的实现类上,用于将持久层的对象配置到spring的IOC容器中,但是以后我们整合了Mybatis,这里就变成了Mapper接口,而Mapper接口是由Mybatis和Spring的整合包负责扫描的。由于Mybatis整合包想要把Mapper接口背后的代理类加入Spring的IOC容器需要结合Mybatis对Mapper配置文件的解析,所以这个事情是Mybatis和Spring的整合包来完成,将来由Mybatis负责扫描,也不需要使用Repository注解。
1 2 3 4 5
| package com.atguigu.ioc.component; import org.springframework.stereotype.Repository; @Repository public class SoldierDao implements ISoldierDao{ }
|
虽然我们学习的上述四个注解都实现IOC,但是其实他们四个在本质上是没有区别的。通过查看源码我们得知,@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字。对于Spring使用IOC容器管理这些组件来说没有区别。所以@Controller、@Service、@Repository这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。
注意:虽然它们本质上一样,但是为了代码的可读性,为了程序结构严谨我们肯定不能随便胡乱标记。
4. 给Bean设置name
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
4.1 默认情况
类名首字母小写就是bean的id。例如:SoldierController类对应的bean的id就是soldierController。
4.2 使用value属性指定
1 2 3
| @Controller(value = "tianDog") public class SoldierController { }
|
当注解中只设置一个属性时,value属性的属性名可以省略:
1 2 3
| @Controller("tianDog") public class SoldierController { }
|
5. 怎么选择
- 如果这个类是你自己写的类,表示你可以在它上面加注解,所以可以使用注解方式进行IOC
- 如果这个类不是你自己写的类,而是第三方依赖中的类,表示你不能在它上面加注解,那么就只能用配置文件方式进行IOC
第二节 依赖注入相关的注解
2.1 注入简单类型的属性
Value注解是用于给IOC容器中的Bean注入简单类型的属性值
1 2 3 4 5 6
| @Service("smallDog") public class SoldierService { @Value("aobama") private String name; }
|
2.2 读取properties中的数据并且进行注入
2.2.1 准备properties配置文件
happyInfo.properties
1
| happy.componentName=aoalfu
|
2.2.2 使用PropertySource注解读取配置文件数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.component;
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component;
@Component("happyComponent") @PropertySource("classpath:happyInfo.properties") public class HappyComponent { @Value("${happy.componentName}") private String componentName;
public String getComponentName() { return componentName; } }
|
2.3 注入Bean类型属性
2.3.1 设定情景
- UserController需要UserService
- UserService需要UserDao
- UserDao需要HappyComponent
- HappyComponent需要componentName
同时在各个组件中声明要调用的方法。
2.3.2 在各个组件中声明成员变量和方法
2.3.2.1 UserController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.atguigu.controller;
import com.atguigu.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;
@Controller("userController") public class UserController { private UserService userService; public void printName(){ System.out.println("打印:" + userService.getName()); } }
|
2.3.2.2 UserServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.atguigu.service.impl;
import com.atguigu.dao.UserDao; import com.atguigu.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
@Service("userService") public class UserServiceImpl implements UserService { private UserDao userDao; @Override public String getName() { return userDao.getName(); } }
|
2.3.2.3 UserDaoImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.dao.impl;
import com.atguigu.component.HappyComponent; import com.atguigu.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository;
@Repository("userDao") public class UserDaoImpl implements UserDao { private HappyComponent happyComponent; @Override public String getName() { return happyComponent.getComponentName(); } }
|
2.3.2.4 HappyComponent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.atguigu.component;
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;
@Component("happyComponent") public class HappyComponent { private String componentName;
public String getComponentName() { return componentName; } }
|
2.3.3 使用Autowired注解进行注入
2.3.3.1 Autowired注解可以使用的位置
用在成员变量上(最常用)
1 2 3 4 5 6 7 8 9 10
| package com.atguigu.controller; import org.springframework.stereotype.Controller; @Controller public class UserController { @Autowired private UserService userService; public void printName(){ System.out.println("打印:" + userService.getName()); } }
|
用在构造器上
1 2 3 4 5 6 7 8
| @Controller public class UserController { private UserService userService; @Autowired public UserController(UserService userService) { this.userService = userService; } }
|
用在方法上
1 2 3 4 5 6 7 8
| @Controller public class UserController { private UserService userService; @Autowired public void setUserService((UserService userService) { this.userService = userService; } }
|
用在参数上
1 2 3 4 5 6 7
| @Controller public class UserController { private UserService userService; public UserController(@Autowired UserService userService) { this.userService = userService; } }
|
2.3.3.2 Autowired工作流程
首先根据所需要的组件类型到IOC容器中查找
- 能够找到唯一的bean:直接执行装配
- 如果完全找不到匹配这个类型的bean:装配失败
- 和所需类型匹配的bean不止一个
- 没有@Qualifier注解:根据@Autowired标记位置成员变量的变量名作为bean的id进行匹配
- 使用@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配
2.3.4 使用Resource注解进行注入
1 2 3 4 5 6 7 8 9 10
| package com.atguigu.ioc.component; import org.springframework.stereotype.Controller; @Controller public class SoldierController { @Resource private SoldierService soldierService; public void getMessage() { soldierService.getMessage(); } }
|
2.3.5 Autowired注解和Resource注解的区别
@Autowired功能虽说非常强大,但是也有些不足之处。比如:比如它跟spring强耦合了,如果换成了JFinal等其他框架,功能就会失效。而@Resource是JSR-250提供的,它是Java标准,绝大部分框架都支持。
除此之外,有些场景使用@Autowired无法满足的要求,改成@Resource却能解决问题。接下来,我们重点看看@Autowired和@Resource的区别。
- @Autowired默认按byType自动装配,而@Resource默认byName自动装配。
- @Autowired只包含一个参数:required,表示是否开启自动注入,默认是true。而@Resource包含七个参数,其中最重要的两个参数是:name 和 type。
- @Autowired如果要使用byName,需要使用@Qualifier一起配合。而@Resource如果指定了name,则用byName自动装配,如果指定了type,则用byType自动装配。
- @Autowired能够用在:构造器、方法、参数、成员变量和注解上,而@Resource能用在:类、成员变量和方法上。
- @Autowired是spring定义的注解,而@Resource是JSR-250定义的注解。
此外,它们的装配顺序不同。
Autowired的装配顺序:
Resource的装配顺序:
- 如果同时指定了name和type:
- 如果指定了name:
- 如果指定了type:
- 如果既没有指定name,也没有指定type:
第三节 纯注解开发
体验纯注解开发,是为了给将来学习SpringBoot打基础。因为在SpringBoot中,就是完全舍弃XML配置文件,全面使用注解来完成主要的配置。
1. 使用配置类取代配置文件
1.1 创建配置类
使用@Configuration注解将一个普通的类标记为Spring的配置类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.configuration;
import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration public class AtguiguSpringConfiguration { }
|
1.2 在配置类中配置包扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.atguigu.configuration;
import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration @ComponentScan("com.atguigu") public class AtguiguSpringConfiguration { }
|
1.3 在配置类中配置bean
对Bean进行IOC的时候,如果是自己编写的类,则可以直接通过IOC注解进行配置,如果是非自己写的类:例如JDK中或者第三方框架中的类,我们可以通过配置文件进行IOC;但是在纯注解中没有了配置文件,所以我们需要使用@Bean注解进行IOC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.atguigu.configuration;
import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
@Configuration @ComponentScan("com.atguigu") @PropertySource("classpath:jdbcInfo.properties") public class AtguiguSpringConfiguration { @Value("${jdbc.username}") private String username;
@Value("${jdbc.password}") private String password;
@Value("${jdbc.url}") private String url;
@Value("${jdbc.driver}") private String driver; @Bean public DataSource getDataSource(){ DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
|
1.4 根据配置类创建IOC容器对象
1 2
| ApplicationContext iocContainerAnnotation = new AnnotationConfigApplicationContext(MyConfiguration.class);
|
1.5 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.atguigu;
import com.atguigu.configuration.AtguiguSpringConfiguration; import com.atguigu.controller.UserController; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestAnnotationOnly { @Test public void testPrintConnection(){ ApplicationContext act = new AnnotationConfigApplicationContext(AtguiguSpringConfiguration.class); UserController userController = (UserController) act.getBean("userController"); userController.printConnection(); } }
|
第四节 Spring整合junit4
1. Spring整合Junit4的好处
- 好处1:不需要自己创建IOC容器对象了
- 好处2:任何需要的bean都可以在测试类中直接享受自动装配
2. 具体操作
2.1 加入依赖
1 2 3 4 5 6 7 8 9
|
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.1</version> <scope>test</scope> </dependency>
|
2.2 创建测试类
如果是使用的配置类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.atguigu;
import com.atguigu.configuration.AtguiguSpringConfiguration; import com.atguigu.controller.UserController; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = AtguiguSpringConfiguration.class) public class TestAnnotationOnly { @Autowired private UserController userController; @Test public void testPrintConnection(){ userController.printConnection(); } }
|
如果是使用的配置文件:
1 2 3 4 5 6 7 8 9 10 11
| @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:spring-application.xml") public class TestSpringAnnotation { @Autowired private UserController userController; @Test public void testPrintConnection(){ userController.printConnection(); } }
|
第五节 内容总结
- 包扫描: 指定要进行组件扫描的包
- IOC 注解:
- Component注解: 三层结构之外的其他类使用
- Controller注解: 表现层的类使用
- Service注解: 业务层的类使用
- Repository注解: 持久层的类使用
- 依赖注入注解:
- 注入Bean:
- Autowired注解,它是byType进行自动注入,如果要byName必须结合Qualifier注解一起使用
- Resource注解,它默认是byName进行自动注入
- 注入简单类型: Value注解,以及使用PropertySource注解引入外部的properties文件
- 注解方式和配置文件方式进行IOC和依赖注入的选择问题:
- 如果是自己写的类就使用注解方式
- 如果是第三方jar中的类就使用配置文件方式
- Spring整合Junit:
- 目的:简化单元测试
- 实现步骤:
- 引入spring-test的依赖
- Junit的依赖版本必须是4.12及以上
- 给单元测试类添加@Runwith(SpringJUnit4ClassRunner.class)
- 给单元测试类添加@ContextConfiguration(locations=”配置文件的路径”或者是classes=配置类.class)
- 直接注入你想使用的IOC容器中的对象就可以直接使用了
- Spring的纯注解开发
- 目的: 为了以后学习SpringBoot做准备,我们项目如果是使用Spring做开发的话是不会用纯注解的
- 步骤:
- 配置类上要添加@Configuration注解标示为配置类
- 配置类上要添加@ComponentScan指定要扫描的包
- 如果要对第三方的类进行IOC配置
- 在配置类中创建一个方法
- 修饰符public
- 返回值是要进行IOC的对象的类型
- 方法体中编写创建IOC对象的代码
- 如果要给这个方法注入一个IOC容器中存在的对象,直接在方法的参数中声明就行了
- 给该方法添加@Bean注解
- 如果是使用纯注解开发,整合Junit的时候,@ContextConfiguration(classes=配置类.class)