吃透Spring框架(三)
1. Spring 相关注解
在讲注解之前我们先看一下啥是注解。
代码格式:@英文单词
,例如:
作用位置:常用在类上或者方法上
用处:简化代码、完成某些功能
所以 Spring 引入注解也是为了简化我们的代码,通过使用简单的注解完成一些功能。
1.1 创建对象相关注解
我们前面在学 IOC 的时候知道如果想让 Spring 创建对象,必须要在配置文件中写 bean 标签。
<bean id="calculateService" class="com.xxl.service.impl.CalculateServiceImpl" />
<bean id="proxyBeanPostProcessor" class="com.xxl.aop.ProxyBeanPostProcessor"/>
<bean id="testMyAspect" class="com.xxl.aop.TestAspect" />
......
可是如果想让 Spring 管理一堆对象,我们就要写一堆 bean 标签。所以 Spring 为了简化代码,提供了一些与创建对象
相关的注解。
1.1.1 @Component
作用:替换 bean 标签,用来创建对象。就是在类上面加了这个注解,就不用在配置文件上写 bean 标签了。
位置:类上面
id 属性:默认首单词首字母小写。
// id 属性:默认首单词首字母小写。
@Component("user")
public class User{
}
1.1.2 @Component 衍生注解
我们在开发程序的时候一般会将程序分层,例如分为控制层(controller),业务层(service),持久层(dao)。
但是 @Component 注解并不能区分这些类属于那些层,所以 Spring 提供了以下衍生注解:
1.@Controller:表示创建控制器对象
@Controller
public class UserController {
}
2.@Service:表示创建业务层对象
@Service
public class UserServiceImpl implements UserService {
}
3.@Repository:表示创建持久层对象
@Repository
public class UserDaoImpl implements UserDao {
}
这三个注解的作用和 @Component 的作用一样,都是用来创建对象。
1.1.3 @Scope
我们知道 Spring 工厂创建的对象默认都是单例的,也就是 bean 标签中 scope 属性默认是 singleton。
@Scope 注解可以用来修改创建对象的 scope 属性。
默认:也就是说你不写 @Scope 注解,默认就是 singleton,所以可以省略。
@Component
// 可以省略不写
@Scope("singleton")
public class User {
}
修改多例:
@Component
@Scope("prototype")
public class User {
}
1.1.4 生命周期相关注解
1.@PostConstruct
初始化方法注解,作用在方法上。用来替换 bean 标签的 init-method 属性。
例如:
@Component
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
// 初始化方法
@PostConstruct
public void init(){
this.name = "王小波";
}
}
测试:
@Test
public void testSpring() {
// 1、获取工厂
ApplicationContext act = new ClassPathXmlApplicationContext("/applicationContext.xml");
// 2、通过工厂类获得对象
User user = (User) act.getBean("user");
System.out.println(user);
}
报错了!这是为什么?
我们先看报错内容:
No bean named 'user'
也就是说找不到这个对象。我们虽然加了 @Component 注解,但是 Spring 不知道啊,所以需要在 Spring 的配置文件中配置注解扫描
:
<context:component-scan base-package="com.xxl"/>
base-package: 添加注解的类所在的包位置。
配置了注解扫描,当程序启动的时候 Spring 会先扫描一下相关的注解,这些注解才会生效。
就比如你去快递驿站拿快递,你看到了自己的快递然后对快递小哥说:"这我的快递我拿走了啊。"但是人家小哥无法确认是你的啊!所以他需要用扫码枪扫一下才能出货!
我们配置注解扫描之后再次测试:
2.@PreDestory(了解即可)
销毁方法注解,作用在方法上。用来替换 bean 标签的 destory-method 属性。
1.2 注入相关注解
1.2.1 @Autowired
我们之前学 DI 的时候知道:注入就是赋值
。
@Autowired 主要是为自定义的类型赋值,例如 service、dao 层的各种类。
@Controller
public class UserController {
@Autowired
private UserService userService;
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
}
@Autowired 是基于类型
进行注入,所注入对象的类型必须和目标变量类型相同或者是他的子类、实现类。
如果想基于名字注入,可以和 @Qualifier
注解连用:
@Autowired
@Qualifier("orderDAOImpl")
private OrderDAO orderDAO;
1.2.2 @Resource
@Resource 注解是 JAVAEE 规范中提供的注解,他和 @Autowired 注解的作用一样, 但是他是基于名字进行注入:
@Resource("orderDAOImpl")
private OrderDAO orderDAO;
在实际开发中,用 @Autowired 注解比较多一点。
1.2.3 案例
Product 类
@Component
public class Product {
private String productName;
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@Override
public String toString() {
return "Product{" +
"productName='" + productName + '\'' +
'}';
}
@PostConstruct
public void init(){
this.productName = "西瓜";
}
}
User 类:
@Component
public class User {
private String name;
@Autowired
private Product product;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@PostConstruct
public void init(){
this.name = "小明";
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", product=" + product +
'}';
}
}
测试:
@Test
public void testSpring() {
// 1、获取工厂
ApplicationContext act = new ClassPathXmlApplicationContext("/applicationContext.xml");
// 2、通过工厂类获得对象
User user = (User) act.getBean("user");
System.out.println(user);
}
1.3 Spring 配置文件相关注解
1.3.1 @Configuration
@Configuration 注解用于替换 xml 配置文件。
@Configuration
public class SpringConfig {
}
意思就是说你在一个类上面加一个 @Configuration 注解,这个类就可以看成 Spring 的配置类,你就不用再写 xml 文件了。
我们之前是根据 xml 文件创建 Spring 的工厂,那怎样根据配置类创建工厂呢?
有两种方式:
方式一:根据类.class
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
方式二:根据配置类所在的路径
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.xxl");
1.3.2 @Bean
@Bean 注解也是用来创建对象的,相当于spring 配置文件中的 bean 标签。
@Configuration
public class SpringConfig {
@Bean
public Product getProduct(){
return new Product();
}
}
自定义 id 值:
@Configuration
public class SpringConfig {
@Bean("product")
public Product getProduct(){
return new Product();
}
}
不过在实际开发中我们一般会用 @Bean 注解创建一些复杂的对象,例如 Redis、MQ 等一些组件对象。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
1.3.3 @ComponentScan
@ComponentScan 注解相当于 xml 配置文件中的注解扫描
标签:
<context:component-scan base-package="com.xxl"/>
作用:用来扫描@Component 等相关注解
属性:
basePackages:注解所在的包路径
例如:
@Configuration
@ComponentScan(basePackages = "com.xxl")
public class SpringConfig {
}
2. 注解小案例
1.User 类
@Component
public class User {
private String name;
@Autowired
private Product product;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
@PostConstruct
public void init(){
this.name = "渣渣辉";
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", product=" + product +
'}';
}
}
2.Product 类
@Component
public class Product {
private String productName;
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
@Override
public String toString() {
return "Product{" +
"productName='" + productName + '\'' +
'}';
}
}
3.配置类:
@Configuration
@ComponentScan(basePackages = "com.xxl")
public class SpringConfig {
@Bean
public Product product() {
Product product = new Product();
product.setProductName("草莓味的番茄");
return product;
}
}
4.测试
@Test
public void testSpring() {
// 1、获取工厂
ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class);
// 2、通过工厂类获得对象
User user = (User) act.getBean("user");
System.out.println(user);
}
-END-
相关文章
- Spring MVC框架:第七章:REST架构风格
- 吃透Spring框架(一)
- 吃透Spring框架(二)
- 每天20分钟之spring-cloud-gateway基础五动态路由
- Spring中框架
- Springboot整合shiro_spring boot框架介绍
- spring boot整合shiro_Spring框架介绍及使用
- 面试系列-spring-ioc原理
- Spring Core Rce复现
- Spring基础(十):AOP概念和原理
- Spring基础(十七):Spring日志框架和测试支持
- 【Elasticsearch】整合Spring Data Elasticsearch
- Spring Cloud Gateway路由规则的匹配和优先级(一)
- 【愚公系列】2023年04月 Java教学课程 131-Spring框架的简介和基本使用
- Spring Cloud Task 任务开发-实现任务处理逻辑(一)
- MyBatis与Spring的整合实例详解
- Maven搭建SSH(Struts2+Spring+Hibernate)框架入门教程(附带实例)
- spring架构利器:JFinal MySQL Spring(jfinalmysql)
- 使用Spring框架实现远程服务暴露与调用