Spring 对象的存储

1. 使用 Bean 标签

在 Spring 的配置文件中添加 Bean 标签, 可以把指定类的实例以指定的名称 (id) 存储到容器中, 将来可以使用这个名称获取到该实例.

1.1 创建 Bean 类

public class Student {
    public void sayHello(){
        System.out.println("hello Student!");
    }
}

1.2 将 Bean 类注册到容器中

在这里插入图片描述

通过这个 bean 标签就将 Student 类的实例存储到容器中了, spring 容器中会以 map 的结构组织这些对象, key 就是我们设置的 id, value 就是 bean 对象.

1.3 获取并使用 bean 对象

public class APP {
    public static void main(String[] args) {
        // 1.获取 spring 上下文.对于容器的一系列操作都是通过这个上下文对象完成的.创建该对象的时候需要指定配置信息.
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 2.调用 getBean 方法获取容器中的 Bean 对象.
        Student student = context.getBean("student", Student.class);
        // 3.使用 bean 对象.
        student.sayHello();
    }
}

代码运行后, 成功获取到对象并打印出了信息.
在这里插入图片描述
注意事项:

a.Bean 对象的名称, 也就是我们在配置文件中添加 bean 标签时指定的 id.

b.getBean方法有很多重载方法, 它支持:

  1. 通过名称 + 类型获取对象.

  2. 只通过类型获取, 如下所示:

            Student student = context.getBean(Student.class);
    

    但是存在隐患的就是如果该类型的对象在容器中存在多个, 则会抛出以下异常:
    在这里插入图片描述

  3. 只通过 id 获取, 如下所示:

            Student student = (Student) context.getBean("student");
    

    但此时返回的 bean 对象类型就是 object, 还需要进行类型的强转!

2. 使用注解

使用上述方式, 每次向容器中存储一个 bean 对象就需要在配置文件中去添加一个 bean 标签, 这显然是很麻烦的, 使用注解可以简化这个流程.

2.1 前置工作, 配置扫描路径.

在使用类注解实现自动往容器中添加对象之前, 需要先在配置文件中设置扫描路径, 这个工作是必须的!!! 因为如果我们不设置扫描路径的话, spring 它是不会去扫描当前项目中的类并读取类上添加的注解.

只需要在配置文件中添加一个 content:component-scan 标签, 标签中添加一个 base-package 属性, 属性的值就是扫描路径.
在这里插入图片描述

2.2 添加类注解存储 Bean 对象

想要将对象存储在 spring 容器中, 有两种注解类型可以实现.

  1. 类注解: @Controller、@Service、@Repository、@Component、@Configuration.
  2. 方法注解: @Bean
2.2.1 @Controller

使用 @Controller 注解存储 bean 的代码示例:

//将该类的实例存储到 spring 容器中去
@Controller
public class UserController {
	public void printHello(){
		System.out.println("from com.demo.controller.UserController: hello!");
	}
}

然后我们在启动类的 main 方法中尝试获取该对象并调用 printHello 方法:

public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserController userController = context.getBean("userController",UserController.class);
        userController.printHello();
    }
}

运行结果:
在这里插入图片描述

2.2.2 @Service

代码示例:

@Service
public class UserService {
	public void printHello(){
		System.out.println("form package com.demo.service.userService:hello!");
	}
}

测试代码:

public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService = context.getBean("userService",UserService.class);
        userService.printHello();
    }
}
2.2.3 @Repository

代码示例:

@Repository
public class UserRepository {
	public void printHello(){
		System.out.println("from package com.demo.repository.UserRepository:hello!");
	}
}

测试代码:

public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
        userRepository.printHello();
    }
}

其余的两个类注解在使用和功能上同上诉三个注解是一致的, 就不过多举例了.

2.3 为什么需要那么多注解

通过上诉示例我们发现, 这几个类注解功能是一致的, 那就是将该类的实例存储到容器中, 那么为什么会有这么多注解呢?

spring 提供这么多注解主要是用于直观的标识某一个类的用途, 让程序员看到这个注解就能大概猜到这个类主要是干嘛的, 起到类似于注释的效果.

比如:

  • @Controller 控制层. 参数验证和拦截相关的功能在这层实现.
  • @Service 服务层. 主要做服务调度.
  • @Repository 持久层. 直接操作数据库.
  • @Configuration 配置层.
  • @Component 存放一些不方便划分进上诉分层的工具组件.

调用流程如下:
在这里插入图片描述

2.4 使用类注解时 Bean 对象的命名规则.

上诉示例中, 我们使用类名首字母小写作为 Bean 对象的名称, 但不总是这样的, 还存在特例. 如下面这个示例:

@Component
public class UComponent {
	public void printHello(){
		System.out.println("from package com.demo.component.UComponent:hello!");
	}
}

当我们尝试使用类名首字母小写, 也就是 “uComponent” 去获取 bean 对象时:

public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UComponent uComponent = context.getBean("uComponent",UComponent.class);
        uComponent.printHello();
    }
}

抛出了异常, 异常原因就是在 spring 容器中不存在一个名称为 uComponent 的对象.

在这里插入图片描述

2.4.1 默认的命名规则

如果在使用类注解时, 没有传递任何的参数, 那么 spring 会调用如下方法生成一个默认的 bean 对象名称.
在这里插入图片描述

该方法最终调用的是 JDK Introspector 中的 decapitalize ⽅法, 源码如下:

    public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

所以默认的命名规则如下:

判断类名的首字母和第二个字母是否都是大写. 如果是, 则 bean 对象的名称就是类名.

如果不是, 则使用类名首字母小写作为 bean 对象的名称.

2.4.2 重命名

当然 spring 也支持我们在使用类注解时, 显示指定 bean 对象的名称.

观察各个注解源码我们发现, 每个注解都提供了一个 String 类型的 value 属性, 它就是用于设置 bean 对象名称的.

在这里插入图片描述

对于上述示例, 我们显示指定 bean 对象的名称为 “uComponent”.

@Component("uComponent")
public class UComponent {
	public void printHello(){
		System.out.println("from package com.demo.component.UComponent:hello!");
	}
}

再使用 “uComponent” 这个名称获取 bean 对象的时候, 就不会报错了.

public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UComponent uComponent = context.getBean("uComponent",UComponent.class);
        uComponent.printHello();
    }
}

运行程序, 成功获取到了对象并调用了它的方法:

在这里插入图片描述

2.5 方法注解 @Bean

方法注解用于添加到一个方法上, 该方法的返回值会被存储到 spring 容器中.

使用 @Bean 注解应当注意的是:

1.通过 @Bean 注解存储到容器中的对象, 默认名称为方法名. 当然可以在使用该注解的时候, 显示指定对象的名称, 并且 spring 允许给一个对象添加多个名称.

@Bean 注解的源码如下, 其中 value 和 name 可以看作是一个属性, 类型是 “String[]”.
在这里插入图片描述

2.@Bean 注解得搭配 Bean 标签或者是类注解一起使用, 即定义该方法的类, 一定得在 spring 容器中存在相应的 Bean 对象. 只有这样 spring 才会扫描该类, 去读取方法上添加的 @Bean 注解, 然后通过存储在容器中的该类的对象来调用此方法, 并将方法的返回值作为一个 Bean 对象存储到容器中.

简单代码示例:

@Controller
public class UserController {
	@Bean({"userService","service","user"})
	public UserService getUserService(){
		return new UserService();
	}
}
public class APP {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // 分别通过 userService, service, user 获取对象
        UserService userService1 = context.getBean("userService",UserService.class);
        UserService userService2 = context.getBean("service",UserService.class);
        UserService userService3 = context.getBean("user",UserService.class);
        userService1.printHello();
        userService2.printHello();
        userService3.printHello();
    }
}

程序的运行结果:
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值