> 文章列表 > 【JavaEE】Spring中存储和获取Bean(使用注解)

【JavaEE】Spring中存储和获取Bean(使用注解)

【JavaEE】Spring中存储和获取Bean(使用注解)

目录

存储Bean

配置文件中设置扫描路径

使用注解存储Bean

五大类注解存储Bean

五大类注解之间的关系

为什么要有五大类注解

@Bean方法注解存储方法返回值

注入Bean

属性注入

Setter方法注入

构造方法注入

@Resource注解


存储Bean

上篇文章的存储Bean是在Spring的配置文件下通过bean标签来把Bean存储到Spring容器中,其中需要设置标签属性id 和 name,还是比较麻烦的,接下来介绍一种更为简单也最为常用的方法来存储Bean。


配置文件中设置扫描路径

首先还是要在配置文佳中设置一下。这里需要设置的是要存储的Bean对象的路径。

比如我想把test包下面的这几个类存储到Spring中,此时就需要在配置文件中写一下扫描的路径。

<?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.test"></content:component-scan>
</beans>

有关扫描路径需要注意的点:

1. 只有在扫描路径下的类,加了注解的才能被存储到Spring中

2. 扫描路径是可以提升效率的,不至于在整个项目中找要存储的类 


使用注解存储Bean

上述工作完成后就可以通过注解存储Bean。注解分为两大类,一类是类注解,一类是方法注解

五大类注解存储Bean

这五个注解分别是  @Controller  @Component  @Configuration  @Repository  @Service

使用演示:

package com.test;import org.springframework.stereotype.Controller;@Controller
public class UserController {public void doController() {System.out.println("doUserController");}
}
import com.test.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {// 获取到Spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 测试ControllerUserController userController = context.getBean("userController", UserController.class);userController.doController();}
}

上面获取到Bean时,第一个参数直接就是把类的第一个字母小写了(大驼峰变成小驼峰)

这只是其中的一个对Bean名字的处理方式,接下来来看另外一种。

package com.test;import org.springframework.stereotype.Controller;// 当类的第一、二的字母都是大写的情况
@Controller
public class UController {public void doController() {System.out.println("doUController");}
}

 

 

为什么会有两个处理情况,通过查看源码可知。

其他四个注解也都是相同的命名规则,也是相同的用法,就不一一演示了。

小结:

1. 使用注解来存储的前提是配置文件中已经设置好了路径

2. 只有在配置文件路径下加了注解才能把Bean存储到Spring中,二者同时成立才可以

3. 取出Spring的bean时,有两种方法:

    a. 如果类名的前两个字母并非都为大写字母,则在取的时候变成首字母小写

    b. 如果前两个字母都是大写,在取的时候使用原类名即可

五大类注解之间的关系

可以看出,@Service  @Repository  @Controller @Configuration  这四个注解都是相当于 拓展了 @Component 这个注解,所以它们的使用方式基本都一致。

为什么要有五大类注解

当程序员看到五大类注解后,就会知道这个类具体是干什么的。


@Bean方法注解存储方法返回值

1. 在配置文件中把把方法所在的类的路径配置好

2. 在方法上加@Bean注解,同时在方法所在的类上面加上五大类注解

package com.test.component;import com.test.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
public class UserBeans {@Beanpublic User getUserById() {User user = new User();user.setUserId(1);user.setUserName("张三");user.setUserAge(20);return user;}
}

import com.test.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App {public static void main(String[] args) {// 获取到Spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 测试Bean注解User user = context.getBean("getUserById", User.class);System.out.println(user.getUserName());}
}

如果不加类注解:

上面获取到方法返回的Bean是通过方法名,这和之前五大注解的获取Bean又是另外一套规则。但是通过方法名获取通常是不使用的,我们可以在@Bean注解后重写命名,通过新名字来获取,同时使用原方法名就获取不到Bean了

小结: 

1. @Bean方法注解必须在五大类注解下使用(被五大类修饰的类)

2. 该注解如果没用重命名,那么直接使用方法名就可以获取到Bean

3. 如果重命名后,只能使用新的名字,方法名无法继续使用

4. 新名字可以有很多,使用数组保存

5. 该注解是把方法的返回值存入到Spring中,如果方法没有返回值,就不能使用该注解


注入Bean

把对象从Spring中取出来到某个类中使用。

属性注入

package com.test.service;// 测试从Spring中拿user对象注入UserController类中import com.test.entity.User;
import org.springframework.stereotype.Service;@Service()
public class UserService {// 实际上要连接数据库通过id查询到对象public User getUser(Integer id) {User user = new User();user.setUserName("张三");user.setUserId(123);user.setUserAge(20);return user;}}
package com.test.controller;import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {// 通过属性注入@Autowiredprivate UserService userService;public User getUserByAttribute(Integer id) {return userService.getUser(id);}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {// 获取到Spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 获取到Bean对象UserController userController = context.getBean("userController", UserController.class);System.out.println(userController.getUserByAttribute(123).toString());}
}

优点:

  1. 高效便捷:使用属性注入时,无需编写额外的构造方法或Setter方法,可以大大降低代码量并提高开发效率。

  2. 可读性强,很容易从代码层面看出有哪些Bean被注入了

 缺点:

  1. 无法注入final修饰的修饰的对象。因为final修饰的对象只能被赋值一次,而在Spring容器中,属性注入是通过反射实现的,它需要通过反射来修改对象的属性值,但是final修饰的对象属性是不可变的,不能被修改,因此无法进行属性注入。
  2. 对象有可能会被修改。因为注入的Bean可以使用很多次。
  3. 只能在IoC容器下使用,其他的不行
  4. 不能保证对象完全初始化  原因有以下两点:

            a:Bean依赖关系不完整,当某个Bean依赖的其他Bean还未完全初始化或者还未注                   入时就会出现这种情况。

            b:Bean的声明周期管理不当(下篇文章讲)

Setter方法注入

package com.test.controller;import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {private UserService userService;// 通过Setter方法注入@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public User getUserBySetter(Integer id) {return userService.getUser(id);}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {// 获取到Spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 获取到Bean对象UserController userController = context.getBean("userController", UserController.class);System.out.println(userController.getUserBySetter(123).toString());}
}

优点:

  1. 灵活性高,相较于构造方法注入,它可以在任何时候注入
  2.  符合单一设计原则(每个方法只传一个对象)

缺点:

  1. 不能注入final修饰的对象。只用Java8及以下的不可以,原因同上。但是Java9及以后的可以,因为引入了Variable Handles的机制,可以通过反射来修改final字段的值。
  2. 对象可能会被修改

构造方法注入

package com.test.controller;import com.test.entity.User;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {private UserService userService;// 通过构造方法注入@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public User getUserByConstructor (Integer id) {return userService.getUser(id);}
}
import com.test.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class App2 {public static void main(String[] args) {// 获取到Spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");// 获取到Bean对象UserController userController = context.getBean("userController", UserController.class);System.out.println(userController.getUserByConstructor(123).toString());}
}

特点:

当只有一个构造方法的时候,@AutoWired这个注解可以省略

因为这是官方推荐使用的方法

优点:

  1. 可以注入一个被final修饰的对象。因为除了一开始就赋值,还可以在构造方法中对final修饰的属性赋值。
  2. 被注入的对象不可变。因为构造方法只能在最开始执行一次。
  3. 可以保证被注入的对象完全初始化
  4. 通用性更好,可以在IoC之外的地方使用。

@Resource注解

这是JDK提供的注入Bean的注解,和@AutoWired有以下的区别。

  • @Resource是JDK提供的,@AutoWired是Spring提供的
  • @Resource只能不能使用构造方法注入,@AutoWired都可以
  • @Resource可以设置很多参数,而@AutoWired只能设置一个

 有什么错误评论区指出。希望可以帮到你。