Spring(一)
bean对象的存储和读取
1.创建一个bean对象,在java当中一个对象被使用多次,就可以称为Bean。
package com.spring.demo;
public class Student {
public void sayHi(){
System.out.println("hi student");
}
}
2.将bean存储到Spring容器当中
<!-- 将 bean(com.spring.demo.Student)存到 Spring 容器中,它的名称叫做 student -->
<bean id="student" class="com.spring.demo.Student"></bean>
解释说明:
3.从Spring容器当中读取bean对象
import com.spring.demo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.创建Spring上下文
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
//2.从Spring容器当中获取到Bean对象
Student student = (Student) context.getBean("student");
//3.使用Bean对象
student.sayHi();
}
}
运行结果:
注意细节问题,如下图所示
除了上述使用的 ApplicationContext接口,还可以使用 BeanFactory接口来创建Spring上下文。
//1.创建Spring上下文
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
//2.从Spring容器当中获取到Bean对象
Student student = (Student) beanFactory.getBean("student");
//3.使用Bean对象
student.sayHi();
运行结果:
问题:既然它们都能够实现同样的功能,为什么有了 ApplicationContext还要有 BeanFactory呢?
请看如下代码:
package com.spring.demo;
public class Student {
public Student() {
System.out.println("Student构造方法被执行");
}
public void sayHi() {
System.out.println("hi student");
}
}
public class App {
public static void main(String[] args) {
//1.得到Spring上下文
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
}
ApplicationContext运行结果:
得出结论:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");这行代码执行结束,就会加载对应的Bean对象(饿加载模式)。
对应的:使用BeanFactory下面行这行代码执行结束,并不会对构造方法进行初始化。
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml")); (懒加载模式)。 当程序执行到这行代码的时候才会有初始化的操作Student student = (Student) beanFactory.getBean("student");
ApplicationContext 和 BeanFactory的区别
1.从继承关系上来说:
BeanFactory提供了基础的访问容器的能⼒,⽽ApplicationContext属于 BeanFactory 的⼦类,它除了继承了
BeanFactory 的所有功能之外,还添加了对国际化,支持资源访问⽀持、以及事件传播等⽅⾯的⽀持。
2.二者的加载时机不同:
ApplicationContext是饿加载,它会一次性将xml文件中的Bean对象进行加载,之后的读取效率会很高。而BeanFactory是懒加载,只有调用getBean的时候,才会去加载对应的Bean对象,因此效率较低。
3:从本质上来说,二者并没有谁好谁坏之分,他们测重点不同,ApplicationContext效率高是通过牺牲内存为代价的,而BeanFactory效率低的同时,也节约了内存空间。
获取Bean对象的三种方式
1.通过名称获取
2.通过类型获取
通过类型获取引发的问题是:如果Spring容器当中一个类型存储了多个实例,那么使用类型获取就会抛NoUniqueBeanDefinitionException。
3. 通过名称+类型获取
Student student = context.getBean("student", Student.class);
Spring 更简单的读取和存储对象
在 Spring 中使⽤注解可以更简单的存储和读取对象。
在进行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">
<content:component-scan base-package="com.java.demo"></content:component-scan>
</beans>
使用类注解(五大类注解)
- @Controller:控制器:用于验证用户请求数据的合法性。(类似于安保系统)
- @Service:服务:编排和调度具体执行方法的。(类似于客服中心)
- @Repository:持久层:和数据库进行交互 (类似于执行者)
- @Component:组件(工具类)
- Configuration:配置项(项目中的一些配置)
@Controller实现Bean存储:
package com.java.demo;
import org.springframework.stereotype.Controller;
@Controller
public class StudentController {
public void sayHi() {
System.out.println("hi");
}
}
注意问题:一定要把注解加上,不加注解会抛异常,如下图所以
读取Bean:
import com.java.demo.StudentController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.获取Spring上下文对象
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
//2.获取Bean
StudentController studentController = context.getBean("studentController", StudentController.class);
//3.使用Bean
studentController.sayHi();
}
}
@Service实现Bean存储
package com.java.demo;
import org.springframework.stereotype.Service;
@Service
public class StudentService {
public void sayHi(){
System.out.println("hi");
}
}
读取Bean:
import com.java.demo.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
//1.获取Spring上下文对象
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
//2.获取Bean
StudentService studentService = context.getBean("studentService", StudentService.class);
//3.使用Bean
studentService.sayHi();
}
}
剩下三个类注解,在使用上和上述两个注解的使用完全一样。
注意事项
- 先配置扫描路径,在存放Bean到Spring容器中。
- 在component-scan下不要忘记加五大类注解,否则将会抛异常。
- <bean>标签可以和component-scan一起使用。
- component-scan下的所有子包下的类只要加了五大类注解,同样可以将对象存储到Spring中
- 五大类注解不可以不在component-scan包下。
五大类注解之间的关系
如下图所示:
<bean>可以和component-scan 一起使用
有时候,某个类放在扫描路径下觉得不合适,但又想将这个对象存放到Spring容器当中,为了满足这种场景,就需要扫描路径和传统的类名+classPath结合使用。
为什么要有这么多注解呢?
虽然它们都能实现相同的功能,但它们也有不同的之处,注解很重要的一个功能就是让开发者一看到注解,就知道这个注解的用途。比如:
- @Controller:表示业务逻辑层
- @Service:服务层
- @Repository:持久层
- @Configuration:配置层
程序的工程分层,调用流程如下:
阿里在标准分层的基础之上,又进行了划分 ,如下图所示:
Bean的命名规则
源码展示:
方法注解 @Bean
类注解是把注解加在类上,方法注解是将注解加在方法上。
有时候我们需要将一个对像作为返回值,然后交给Spring容器来托管,就可以使用这个@Bean。
代码实例:
1.先创建一个是实体类
package com.java.demo.entity;
public class User {
private Integer uid;
private String username;
private Integer age;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", age=" + age +
'}';
}
}
2.将返回的对象存入Spring容器当中
package com.java.demo.component;
import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class UserBeans {
@Bean(name = {"u1","u2"})//Bean重命名
public User user1() {
User user = new User();
user.setUsername("张三");
user.setAge(18);
user.setUid(1);
return user;
}
}
说明:虽然叫方法注解,但是它要搭配上类注解,才能成功的存入Spring容器当中。
3.从Spring容器当中取出bean对象
import com.java.demo.controller.UserController;
import com.java.demo.entity.User;
import com.java.demo.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class APP {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
User user = context.getBean("u1", User.class);
System.out.println(user.toString());
}
}
说明;1.@Bean的命名规则和上述的五大类注解的命名规则不同。默认情况下@Bean存储对象的
名称 = 方法名
2.在使用Bean注解的时候,需要搭配上上述的五大类注解一起使用。
3.@Bean可以重命名,当@bean进行重命名之后,默认方法名的方式无法获取到bean对象。
对象注入
//对象注入:将存储在Spring容器当中的bean对象,注入到当前类中。对象注入有三种方式:
//1.属性注入
@Autowired
private UserService userService;
//2.setter注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
//3.构造方法注入
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
userService.age = 20;
}
三种注入对象的优缺点分析:
1.属性注入:
2.setter注入:
3.构造方法注入: