Spring中存对象和取对象的方式详解
作者:it小婷
本文我来介绍一种更简单的存储对象方式和取对象方式,跟上我的节奏,我们开始吧!!
透露一下:Spring中更简单的存对象与取对象的方式是注解。
给大家插个题外话(了解即可),注解实现有两种方式:1.在编译的时候,把注解替换成相关代码,并添加到我们原来的代码中。2.拦截方法,当程序执行到某个方法时,会执行拦截,在执行之前或之后或之中进行一些操作(与我们写的注解有关)。
1.存储对象(Bean)
在上一篇我们存储对象是在配置文件中添加<bean>标签,但这样其实很麻烦,我们每次都得去那添加一个。所以为了简化,我们可以在配置文件中配置扫描路径,然后通过注解来存储对象。
1.1配置扫描路径(重要!!!)
在使用的时候,把下面这段代码放到你的配置文件中,把<content>标签中的包名替换成你项目需要扫描的包名。(这个搭配注解来实现存储对象)
<?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="包名"></content:component-scan> </beans>
为什么会配置这个扫描路径呢?举个例子吧,假设你找个人,你是从整个中国一个一个找好找还是从一个村里找好找。所以嘛,Spring也是这样呀,你给它配置了扫描包,Spring就会从这个包里一个一个找,看哪些添加了注解(需要Spring帮忙创建对象的),他就会把哪些类存储起来。
1.如果我们配置的扫描包中存在子类,里面的注解也是会被扫描的。
2.如果我创建的类在扫描包外面,此时我用相关注解也没有用的,因为根本不会扫这个类!
3.那如果我的类就是在扫描包外面,但是欸,我还是想交给Spring创建对象,肿么办呢?好说嘛!用我上一篇存储Bean的方法,扫描包可以与Bean同时生效的。
4.我们设置了扫描包,没有添加注解,这样也是没办法将对象存储到Spring中的。(两个要搭配使用!!!)
1.2添加注解存储对象
将对象存储到Spring中,有两种可以实现,一种是类注解,一种是方法注解。
1.2.1类注解
类注解有五种:@Controller @Service @Component @Repository @Configuration。
我先来说一下,为啥有这么多类注解。简单来说,为了让程序员看到类注解后更直观的知道这个类是干什么的。JavaEE上有标准分层(至少三层):控制层,业务层,数据层。当然也有更多层的划分,大家可以看阿里巴巴Java开发手册。
控制层主要用于与用户交互,业务层主要用于处理一些业务,数据层主要与数据库进行交互。不同层干不同事,所以也就出来了不同的注解。
1.2.1.1@Controller
这个注解主要用于控制层中。代码如下:
@Controller//通过这个注解将对象存储到Spring中 public class StudentController { public void study() { System.out.println("控制层aaaa"); } }
1.2.1.2@Service
这个注解一般都是用于业务层的。
@Service//通过这个注解存储对象 public class StudentService { public void eat() { System.out.println("业务层啊啊啊"); } }
1.2.1.3@Repository
这个注解用在Dao层,也即是数据层。
@Repository public class StudentMapper { public void study() { System.out.println("我是数据层"); } }
1.2.1.4@Component
这个用于哪呢?当我们进行一些操作不属于三层中的任何一层的时候,我们就可以用这个注解。
@Component public class Test { public void test() { System.out.println("保密功能"); } }
1.2.1.5@Configuration
这个一般都是用于配置类上。
@Configuration public class Test1 { public void set() { System.out.println("配置类"); } }
1.2.1.6五大类注解的关系
这五大类注解其实本质都一样,都是为了将对象存储到Spring中。并且@Controller / @Service / @Repository / @Configuration这几个的源码中都存在@Component,可以认为这四个注解均为@Component的子类,或者均为@Component的扩展。
1.2.1.7通过类注解将对象存储到Spring中的命名规则
- 当我们创建的类名为比较标准的大驼峰形式,Spring提供的对象名为首字母小写,其余不动的形式。
- 如果类名首字母和第二个字母都为大写,提供的对象名为原类名。
- 除了第二条外,默认情况下都是Spring提供的对象名为首字母小写,其余不动的形式。
1.2.2方法注解
1.2.2.1使用与注意事项
方法注解为@Bean。顾名思义,该注解用到方法上。
创建一个User类,并且创建一个Users类,我们来使用一下。
//User类 public class User { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } //Users类 @Component public class Users { @Bean public User user1() { User user = new User(); user.setAge(18); user.setName("张三"); user.setId(1); return user; } }
注意事项:
1.@Bean注解必须搭配五大类注解使用,否则会报错的!(为了Spring执行的性能)
2.通过方法注解将对象存储到Spring中命名规则为(默认情况下)对象名等于方法名。
3.方法的返回类型必须存在,且必须为一个类。
4.我们可能不同类却存在相同方法名的方法,此时如果我们仍采用方法名作为对象id来获取对象,此时会出现覆盖。最后只有一个结果,而且还不一定是我们想要拿到的那个对象。我们有两种方法进行解决:一种是通过注解@Order注解来给其排序,值越小的优先级越高,越先执行。(但是也会覆盖)最后呈现的结果为值最大的。另外一种是给Bean重命名。
5.当我们对同一类型使用多个@Bean时,通过注入的方式注入对象会报错的,因为有多个Bean了,Spring不知道用哪个了。有两种解决方法:(1)注入的时候,使用Resource注解,并且指定对象名,通过name属性;(2)使用@Qualifier注解的value属性来设置注入的名称(必须结合Autowired使用)。
1.2.2.2Bean重命名
由于上面我们提到了当用默认的提供名字的时候可能会出现误差,所以我们可以对方法上面的@Bean进行重命名。说白了也就是对存储到Spring种的对象指定好名字。
//可以只指定一个名字 @Bean(name = "user")//这里可以用name=...也可以用value=..... public User user1() { User user = new User(); user.setAge(18); user.setName("张三"); user.setId(1); System.out.println(1); return user; } //也可以指定多个名字(用哪个都可以) @Bean(name = {"user","use","custom"})//这里可以用name=...也可以用value=..... public User user1() { User user = new User(); user.setAge(18); user.setName("张三"); user.setId(1); System.out.println(1); return user; }
但是,当我们重命名以后,就不可以再用方法名(Spring默认提供的名字)来取出对象了,除非你将重命名后的名字设置为了方法名。
2.取出对象
我在上一篇文章中,叙述了取出对象的方法,正常来说,我们仍这样去取出最终对象。但是在一些类中用到另外的类的时候,我们可以有简单方法呀,也就是对象注入。
对象注入有三种方式:属性注入;setters方法注入;构造方法注入。
@Autowired是先通过类型进行查找,如果发现有多个,然后通过名称(根据我们定义的属性后面,我们定义的变量名查找)查找。(装配顺序)
@Qualifier必须和@Autowired一起使用,@Qualifier通过名字来进行注入。
@Resource先根据名称(如果有多个相同的名称)查再根据类型查。
@Value注入普通类型属性。
2.1属性注入
@Controller public class StudentController { @Autowired public StudentService studentService;//在控制类中引入了另外一个类,为了更方便使用,我们这里采用对象注入方式注入对象。 public void study() { System.out.println("控制层aaaa"); } }
属性注入就是通过@AutoWired注解来完成的。将这个注解放在当前类中引入的另外类最为成员变量的上面即可。
优点:很简单。
缺点:
1.对于有final修饰的变量无法无法进行注入。
2.兼容性差,只使用于IoC容器。
3.风险更大,更容易违背单一设计原则。(比如在服务层,我们就想处理一套业务,但通过这个我们可以进行多套业务)
2.2setters方法注入
也就是通过setters方法进行注入
@Controller public class StudentController { private StudentService studentService; //添加setter方法,并添加注解(注入对象) @Autowired public void setStudentService(StudentService studentService) { this.studentService = studentService; } public void study() { System.out.println("控制层aaaa"); } }
优点:符合单一设计规则,每个Setter方法只有一个参数。
缺点:
1.不能注入不可变对象(final修饰的)
2.使用setter注入的对象可能被修改。
2.3构造方法注入
也就是通过构造方法来注入对象。
@Controller public class StudentController { private StudentService studentService; //通过构造方法来注入了 @Autowired public StudentController(StudentService studentService) { this.studentService = studentService; } public void setStudentService(StudentService studentService) { this.studentService = studentService; } public void study() { System.out.println("控制层aaaa"); } }
1.如果当前类只有这样的一个构造方法,@Autowired这个注解是可以省略的。
优点:
1.可以注入不可变对象(final修饰的)为什么呢?因为被final修饰的变量必须被复制,要不直接复制,要不就是在构造方法中复制。
2.注入对象不会被改变的,构造方法只会执行一次。
3.构造方法注入可以保证完全被初始化。
4.通用性更好。
2.4另外种注入关键字@Resource
和@Autowired相同之处:
- 都是进行注入。
不同之处:
- @Autowired来自Spring而@Resource来自JDK
- 与@Autowired相比,@Resource支持更多参数,我们可以设置name等于什么,根据名称注入Bean。
- @Autowired可以用于三种注入方式中,而@Resource只可以用在Setter和属性注入中。
以上就是Spring中存对象和取对象的方式详解的详细内容,更多关于Spring存对象和取对象的资料请关注脚本之家其它相关文章!