Spring更简单的读取和存储对象

Spring更简单的读取和存储对象

经过前面的学习,我们已经可以实现基本的 Spring 读取和存储对象的操作了,但在操作的过程中我们发现读取和存储对象并没有想象中的那么“简单”,所以接下来我们要学习更加简单的操作 Bean 对象的方法。
在 Spring 中想要更简单的存储和读取对象的核心是使用注解,也就是我们接下来要学习 Spring 中的相关注解,来存储和读取 Bean 对象。

1.存储Bean对象

之前我们存储 Bean 时,需要在 spring-config 中添加一行bean,如下图
在这里插入图片描述
而现在我们只需要⼀个注解就可以替代之前要写一行配置的尴尬了,不过在开始存储对象之前,我们先要来点准备工作。

1.1前置工作:配置扫描路径

很重要!!如果不配置,接下来所有的操作不生效!!!!
之前的步骤不变,在spring-config.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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.service"></content:component-scan>
</beans>

下图这里换成你的bean对象存放的包下,下图的意思是配置bean的扫描根路径,只有当前目录下的类才会扫描释放添加了注释,如果添加了注释,就将这些添加了注释的类存放到ioc容器中
在这里插入图片描述
在这里插入图片描述

1.2添加注解存储bean对象

想要将对象存储在 Spring 中,有两种注解类型可以实现:

  1. 类注解:@Controller、@Service、@Repository、@Component、@Configuration。
  2. ⽅法注解:@Bean。
    接下来我们分别来看

类注解

1.2.1@Controller(控制器存储)

它是前端所有访问请求的入口,校验参数的合法性(安检系统),如果前端传过来的参数不合规范,后续都不再进行

@Controller // 将对象存储到 Spring 中
public class User {
 public void sayHi() {
 System.out.println("Hi");
 }
}
public class Application {
 public static void main(String[] args) {
 // 1.得到 spring 上下⽂
 ApplicationContext context =
 new ClassPathXmlApplicationContext("spring-config.xml");
 // 2.得到 bean
 User user = context.getBean(
"user",User.class);//前一个参数是首个单词小写,小驼峰
 // 3.调⽤ bean ⽅法
 user.sayHi();
 }
}

其他也类似,只不过把注解改了

1.2.2@Service(服务存储)

这是一个业务组装注解,它会告诉你这个业务会用到哪些方法,会调用几个接口,它只是单纯的调用方法,不会执行这个方法

相当于客服中心,比如你去坐飞机,不知道流程,你去前台问具体流程,然后你跟前台说,你想找人待着你去,前台就打电话给保安带着你去了(调用保安,没自己亲自带着去)

1.2.3@Repository(仓库存储)

它才是实际的一个业务执行处理,这一层是数据持久层,是实际和数据库打交道的

1.2.4 @Component(组件存储)

这一层是工具类层,可以理解成基础的工具,比如我去吃饭,人家店里的基础工具就是椅子

1.2.5Configuration(配置存储)

这一层是配置层,针对于当前项目做一些设置,比如我设置当前项目的端口号,当前系统的session存储时间

既然功能是⼀样的,为什么需要这么多的类注解呢?
这五个类注解就相当于车牌号的前置内容,当你看到这个前置内容之后你就知道是哪里的车了,比如天津是津,陕西是陕,然后西安是A,当你看到陕A的时候就知道是西安的,上面五个类注解也一样,当你看到哪个注解就知道对应业务的哪个方面
比如:
@Controller:表示的是业务逻辑层;
@Servie:服务层;
@Repository:持久层;
@Configuration:配置层。
程序的工程分层,调用流程如下:
在这里插入图片描述
这五个类注解关系是怎么样的呢?
其他四个注解都是基于component来实现的,也就是component是父亲,其他四个是儿子
在这里插入图片描述

只会扫描自己设置的包底下的包,及其类在这里插入图片描述

类注解存储bean命名问题

在这里插入图片描述
为什么这么设计呢?
具体看Bean生成名称源代码
这个方法所在的包是在java底下的,命名规则是java的,不是spring框架的
在这里插入图片描述
在这里插入图片描述
因此命名规则是:
满足首字母大写,第二个字母小写的话,就返回类名小驼峰,否则返回原类名

方法注解

@Bean

@Bean:将当前方法返回的对象存储到 IoC 容器

@Bean使用时候的注意事项

在 Spring 框架的设计中,方法注解 @Bean 要配合类注解才能将对象正常的存储到 Spring 容器中

@Component
public class Articles {

    @Bean("article") // 将当前方法返回的对象存储到 IoC 容器
    public ArticleInfo getArt(){
        // 伪代码
        //不要在乎new这个对象,实际开发中都是准备好了的,这里只是为了举例子
        ArticleInfo articleInfo = new ArticleInfo();
        articleInfo.setAid(1);
        articleInfo.setTitle("标题?");
        articleInfo.setContent("今天周一!!!");
        articleInfo.setCreatetime(LocalDateTime.now());
        return articleInfo;
    }
}
ArticleInfo articleInfo=context.getBean("getArt",ArticleInfo.class)

和bean配合使用的类注解所注释的类也会被存储到容器中,也就是说不仅ArticleInfo 被存储到了容器,Articles 也存储到了容器

@Bean获取时候的注意事项

1.@Bean的默认命名=方法名,上述代码就是如此
在这里插入图片描述
2.还可以给@Bean重命名
在这里插入图片描述
@Bean能指定多个名称,而五大类注解最多只可以指定一个名称

3.当@Bean被命名重复的时候
1.在一个类里面,如果多个Bean使用相同的名称,那么程序不会执行出错,但是第一个Bean之后的对象不会被存放到容器中,也就是只有第一次创建Bean的时候会将名称和Bean名称关联起来,后续再有相同的Bean存储的时候,容器会自动忽略
2.不在同一个类里面的时候,可以使用**@Order(参数)**设置调用的先后顺序,这个参数越大,就越先被执行,因此就会执行参数大的@Bean所对应的方法

4.@Bean没有重载可言
在这里插入图片描述

2.获取Bean对象(对象装配)

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入。
对象装配(对象注⼊)的实现方法以下 3 种:

1.属性注入(依赖注入)

属性注⼊是使⽤ @Autowired 实现的
下面示例:将 Service 类注⼊到 Controller 类中。
Service 类的实现代码如下:

import org.springframework.stereotype.Service;
@Service
public class UserService {
 public User getUser(Integer id) {
 // 伪代码,不连接数据库
 User user = new User();
 user.setId(id);
 user.setName("Java-" + id);
 return user;
 }
}

Controller 类的实现代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
 // 注⼊⽅法1:属性注⼊
 @Autowired
 private UserService userService;
 public User getUser(Integer id) {
 return userService.getUser(id);
 }
}

获取 Controller 中的 getUser 方法:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserControllerTest {
 public static void main(String[] args) {
 ApplicationContext context =
 new ClassPathXmlApplicationContext("spring-config.xml");
 UserController userController = context.getBean(UserController.cla
ss);
 System.out.println(userController.getUser(1).toString());
 }
}

最终结果如下
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
优点:使用简单
缺点:
1.功能性问题:无法注入final修饰的变量,要想注入final修饰的变量,可以给被final修饰的变量初始化,或者在构造方法里初始化final
在这里插入图片描述
2.通用性问题:使用Autowired只能适应于IoC容器,因为Autowired依赖于ioc容器的,有ioc容器才有Autowired的
3.设计原则问题:更容易违背单一设计原则。
使用属性注入的方式,因为使用起来很简单,所以开发者很容易在一个类中同时注入多个对象,而这些对象的注入是否有必要?是否符合程序设计中的单一职责原则?就变成了一个问题。但可以肯定的是,注入实现越简单,那么滥用它的概率也越大,所以出现违背单一职责原则的概率也越大。注意:这里强调的是违背设计原则(单一职责)的可能性,而不是一定会违背设计原则,二者有着本质的区别。

2.Setter注入

@RestController
public class UserController {
    // Setter 注入
    private UserService userService;

    @Autowired
    //Autowired不能省略
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("/add")
    public UserInfo add(String username, String password) {
        return userService.add(username, password);
    }
}

优点:通常Setter只set一个属性,所以setter注入更符合单一设计原则
缺点:
1.无法注入一个final修饰的变量
2.Setter注入的对象可能被修改。因为setter本来是一个方法,既然是一个方法就有可能被多次调用和修改

3.构造方法注入(官方推荐)

在这里插入图片描述
如果当前的类中只有一个构造方法,那么 @Autowired 也可以省略,在setter注入那里不能省略,在这里可以省略,因为构造方法的注入式官方推荐的,官方做了一些优化
如果有多个构造方法就不能省略,因为不知道哪些构造方法需要注入,哪些不需要注入,这时候就需要加上Autowired 了
优点:
1.可以注入一个final修饰的变量了
2.注入的对象不会被修改,因为构造方法只执行一次
3.可以保证注入对象会被完全初始化,因为构造方法执行的时机是比较靠前的
4.通用性更好。构造方法和属性注入不同,构造方法注入可适用于任何环境,无论是 IoC 框架还是非 IoC 框架,构造方法注入的代码都是通用的,所以它的通用性更好。
缺点:
1.写法比属性注入更复杂
2.无法解决循环依赖的问题

@Resource:另⼀种注入关键字

在进行类注入时,除了可以使⽤ @Autowired 关键字之外,我们还可以使用 @Resource 进行注入,如下代码所示:

@Controller
public class UserController {
 // 注⼊
 @Resource
 private UserService userService;
 public User getUser(Integer id) {
 return userService.getUser(id);
 }
}

@Autowired和@Resource区别
1.出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解;

2.使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如name 设置,根据名称获取 Bean。
在获取对象的时候,如果对象有多个,可以用@Resource来设置获取的对象的名字

3.@Autowired 可用于 Setter 注入、构造函数注入和属性注入,而@Resource 只能用于 Setter 注入和属性注入,不能用于构造函数注入。

4.idea兼容性不同:使用@Autowired 在idea专业版下可能会误报,而@Resource 则不会。
因为@Autowired 是spring框架提供的,在jvm加载的时候是先加载java的jdk的(@Resource 就是jdk提供的),后加载spring框架的

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值