在Spring 中想要更简单的存储和读取对象的核心是使用注解,也就是我们接下来要学习Spring 中的相关注解,来存储和读取 Bean对象。
之前我们存储Bean时,需要在spring-config中添加一行bean注册内容才行,如下图所示:

而现在我们只需要一个注解就可以替代之前要写一行配置的尴尬了,不过在开始存储对象之前,我们先要来点准备工作。
注意∶想要将对象成功的存储到Spring 中,我们需要配置一下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到Spring中。
在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">
<!-- 配置spring扫描的根路径(此根路径下的所有spring存对象的注解才能生效)-->
<content:component-scan base-package="这里写自己的包名,如:com.bit">
</content:component-scan>
</beans>
想要将对象存储在Spring中,有两种注解类型可以实现:
:@Controller、@Service、@Repository、@Component、@Configuration。@Bean.使用@Controller存储bean的代码如下所示:
import org.springframework.stereotype.Controller;
@Controller //表示将当前的类注册到Spring当中
public class UserController {
/**
* 对象中的测试方法
* @param name
*/
public void sayHi(String name){
System.out.println("Hi,Controller:" +name);
}
}
使用之前读取对象的方式来读取上面的UserController对象,如下代码所示:
import com.bit.Controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Spring 启动类(为了方便演示Spring的功能而创建)
*/
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//2.从Spring中获得存入的对象(id默认的规则是将存入的类的首字母小写)
UserController userController = context.getBean("userController",UserController.class);
userController.sayHi("hello");
}
}

@Service
public class UserService {
public void sayHi(String name)
{
System.out.println("Hi,Service" + name);
}
}
读取 bean 的代码:
import com.bit.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//得到Service
UserService userService = context.getBean("userService",UserService.class);
userService.sayHi("world");
}
}

使用@Repository存储bean 的代码如下所示:
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
public void sayHi(String name){
System.out.println("Hi UserRepository:" + name);
}
}
读取 bean 的代码:
import com.bit.dao.UserRepository;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Spring 启动类(为了方便演示Spring的功能而创建)
*/
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//得到Repository
UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
userRepository.sayHi("MySql");
}
}

使用@Component存储bean 的代码如下所示:
import org.springframework.stereotype.Component;
@Component
public class UserComponent {
public void sayHi(String name){
System.out.println("Hi UserComponent:" + name);
}
}
读取 bean 的代码:
import com.bit.util.UserComponent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//得到 Component
UserComponent userComponent = context.getBean("UserComponent",UserComponent.class);
userComponent.sayHi("user");
}
}

使用@Configuration存储bean 的代码如下所示:
import org.springframework.context.annotation.Configuration;
@Configuration
public class UserConfiguration {
public void sayHi(String name){
System.out.println("Hi,Configuration:" + name);
}
}
读取 bean 的代码:
import com.bit.config.UserConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//得到Configuration
UserConfiguration userConfiguration = context.getBean("userConfiguration",UserConfiguration.class);
userConfiguration.sayHi("Spring");
}
}

这么多的类注解,就是让程序员看到类注解之后,就能直接了解当前类的用途,比如:
@Controller:表示的是业务逻辑层;@Servie:服务层;@Repository:持久层;@Configuration:配置层。程序的工程分层,调用流程如下:

查看@Controller /@Service /@Repository /@Configuration等注解的源码发现:

其实这些注解里面都有一个注解@Component,说明它们本身就是属于@Component 的“子类”。
通过上面示例,我们可以看出,通常我们bean使用的都是标准的大驼峰命名,而读取的时候首字母小写就可以获取到 bean 了;
但是当首字母和第二个字母都是大写时,上面的命名规则就不能正常读取到 bean 了,这时就需要直接用类名命名就可以获取到bean了。
类注解是添加到某个类上的,而方法注解是放到某个方法上的,在Spring框架的设计中,方法注解@Bean要配合类注解才能将对象正常的存储到Spring容器中。
如以下代码的实现:
首先需要创建一个User类,并重写里面的toString方法:
public class User {
private int id;
private String name;
private int age;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + 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;
}
}
再写UserBean 类:方法注解@Bean要配合类注解(@Component)才能将对象正常的存储到Spring容器中
package com.bit.util;
import com.bit.Model.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBean {
//Bean可以有多个别名,但是使用了别名之后,就不能使用方法名获取到对象了
@Bean(name = {"u1","userInfo"})
public User user1(){
//伪代码来构建对象
User user = new User();
user.setId(1);
user.setAge(15);
user.setName("zhangsan");
return user;
}
@Bean(name = "u2")
public User user2(){
//伪代码来构建对象
User user = new User();
user.setId(2);
user.setAge(18);
user.setName("lisi");
return user;
}
}
可以通过设置name属性给Bean对象进行重命名操作:
这个重命名的 name 其实是⼀个数组,一个 bean 可以有多个名字。重命名之后,只能使用重命名之后的名字来获取到bean对象,不能使用方法名获取到对象了。
当没有设置name属性时,那么bean默认的名称就是方法名,当设置了name属性之后,只能通过重命名的name属性对应的值来获取;重命名之后再使用方法名就获取不到bean对象了。
获取bean对象:
public class Application {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
//未重命名之前用方法名就可以获取bean
User user = context.getBean("u1",User.class);
System.out.println(user);
}
}
获取 bean对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注入。
从容器中将对象读取出来。
对象装配(对象注入)的实现方法以下3种:
属性注入是使用@Autowired实现的,将Service类注入到Controller类中。
Service类的实现代码如下:
package com.bit.service;
import com.bit.Model.User;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public User findUserById(int id){
User user = new User();
if(id == 1){
user.setId(1);
user.setName("张三");
user.setAge(10);
}else{
user.setId(2);
user.setName("李四");
user.setAge(20);
}
return user;
}
UserController 实现代码如下:
package com.bit.Controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller //表示将当前的类注册到Spring当中
public class UserController {
//1.属性注册 从Spring中获取一个对象,并注入到当前类
@Autowired
private UserService userService;
/**
* 根据用户id查询用户对象
* @param id
* @return
*/
public User findUserById(Integer id){
if(null == id){
//无效参数
return new User();
}
return userService.findUserById(id);
}
}
获取controller中的findUserById()方法:
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//方式一
UserController controller = context.getBean("userController", UserController.class);
User user = controller.findUserById(1);
//打印user对象
System.out.println(user);
}
}

构造方法注入是在类的构造方法中实现注入,如下代码所示:
package com.bit.Controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController2 {
//1.将UserService注入到当前类(使用set注入的方式)
//定义属性
private UserService userService;
@Autowired
//生成属性的set方法,给属性添加Autowired注解
public UserController2(UserService userService) {
this.userService = userService;
}
//2.在方法里面调用UserService的查询方法,返回用户对象
public User findUserById(Integer id){
return userService.findUserById(id);
}
}
获取controller中的findUserById()方法:
import com.bit.Controller.UserController2;
import com.bit.Model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//方式二
UserController2 controller2 = (UserController2)context.getBean("UserController2");
User user = controller2.findUserById(2);
System.out.println(user);
}
}

Setter注入和属性的Setter方法实现类似,只不过在设置set方法的时候需要加上@Autowired注解,如下代码所示:
package com.bit.Controller;
import com.bit.Model.User;
import com.bit.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController3 {
//方式三:
//3.1定义一个私有对象
private UserService userService;
@Autowired
//3.2 生成属性的set方法,给属性添加Autowired注解
public void setUserService(UserService userService) {
this.userService = userService;
}
/**
* 查询用户对象的方法
* @param id
* @return
*/
public User finUserByiD(Integer id){
return this.userService.findUserById(id);
}
}
获取controller3 :
public class App {
public static void main(String[] args) {
//1.先获取对象的上下文
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
//方式三
UserController3 controller3 = context.getBean("userController3", UserController3.class);
User user = controller3.finUserByiD(2);
System.out.println(user);
}
}

在进行类注入时,除了可以使用@Autowired关键字之外,我们还可以使用@Resource进行注入。
注意:@Resource支持属性注入和Setter注入,但不支持构造方法注入。
@Autowired 来自于Spring,而@Resource来自于JDK的注解;@Autowired 来说,@Resource支持更多的参数设置,例如name、type设置,根据名称获取 Bean。而@Autowired 只支持required参数设置。@Autowired支持属性注入、构造方法注入和Setter注入,而@Resource不支持构造方法注入。当出现以下多个Bean,返回同一对象类型时程序会报错,如下代码所示:
@Bean将一个类型的对象注入多次的问题:
解决方案:
@Controller //表示将当前的类注册到Spring当中
public class UserController {
@Autowired
private User user1;
/**
* 对象中的测试方法
* @param name
*/
public void sayHi(String name){
System.out.println("User :" + user1);
}
}
@Controller //表示将当前的类注册到Spring当中
public class UserController {
@Resource(name = "user1")
private User user;
/**
* 对象中的测试方法
* @param name
*/
public void sayHi(String name){
System.out.println("User :" + user);
}
}
@Autowired+@Qualifier 来筛选bean对象@Controller //表示将当前的类注册到Spring当中
public class UserController {
@Autowired
@Qualifier(value="user1")
private User user;
/**
* 对象中的测试方法
* @param name
*/
public void sayHi(String name){
System.out.println("User :" + user);
}
}
以上。