Spring IoC详解
IoC详解
前面我们提到IoC控制反转,就是将对象的控制权交给Spring的IoC容器,由IoC容器创建及管理对象.
也就是bean的存储.
1)Bean的存储
在之前的入门案例中,要把某个对象交给IoC容器管理,需要下类上添加一个注解: @Component而Spring框架为了更好的服务web应用程序,提供了更丰富的注解.
共有两类注解类型可以实现:
1.类注解: @Controller , @Service , @Repositoty , @Component , @Configuration.
2.方法注解: @Bean
接下来我们分别来看
1.@Controller(控制器存储)
使用@Controller 存储 bean的代码如下所示:
@Controller // 将对象存储到Spring中
public class UserController {
public void sayHi() {
System.out.println("hi, UserController...");
}
}
如何观察这个对象已经存储在Spring容器当中呢?
接下来我们学习如何从Spring容器中获取对象
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//从Spring上下文中获取对象
UserController userController = context.getBean(UserController.class);
//使用对象
userController.sayHi();
}
}
ApplicationContect 翻译过来就是: Spring上下文
因为对象都交给Spring管理了,所以获取对象要从Spring中获取,那么就得先得到Spring的上下文
观察运行结果:
获取bean对象的其他方式
上述代码是根据类型来查找对象,如果Spring容器中,同一个类型存在多个bean的话,怎么来获取呢?
ApplicationContext也提供了其他获取bean的方式,ApplicationContext获取bean对象的功能,是父类BeanFactory提供的功能.
public interface BeanFactory {
//根据bean名称获取bean
Object getBean(String name) throws BeansException;
//根据bean名称和类型获取
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
//根据类型获取
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
}
常用的是上述1,2,4种,这三种方式,获取到的bean是一样的
其中1,2种都涉及到根据名称来获取对象.bean的名称是什么?
Spring bean是Spring框架在运行是管理的对象,Spring会给管理的对象起一个名字
比如学校管理学生,会给每个学生分配一个学号,根据学号,就可以找到对应的学生.
Spring也是如此,给每个对象起一个名字,根据Bean的名称就可以获取到对应的对象.
Bean命名约定
程序开发人员不需要为bean指定名称(BeanId),如果没有显示的提供名称(BeanId),然后使用驼峰式大小写
比如
类名: UserController , Bean的名称为: userController
也有一些特殊情况,当有多个字符并且第一个和第二个字符都是大写时,将保留原始大小写.
比如
类名: UController, Bean的名称为: UController
根据这个命名规则,我们来获取Bean.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
//从Spring上下文中获取对象
//根据Bean类型获取
UserController userController1 = context.getBean(UserController.class);
//根据bean名称获取
UserController userController2 = (UserController) context.getBean("userController");
//根据bean名称 + 类型 获取
UserController userController3 = context.getBean("userController", UserController.class);
System.out.println(userController1);
System.out.println(userController2);
System.out.println(userController3);
}
}
地址一样说明对象是一个
获取bean对象,是父类Factory提供的功能
ApplicationContext VS BeanFactory(常见面试题)
继承关系和功能方面来说: Spring 容器有两个顶级的接口: BeanFactory 和 ApplicationContext .其中 BeanFactory 提供了基础的访问容器的能力,而ApplicationContext 属于 BeanFactory的子类,它除了继承了BeanFactory 的所有功能之外,它还拥有独特的特性, 还添加了对国际化支持,资源访问支持,以及事件传播方面的支持
从性能方面来说: ApplicationContext 是一次性加载并初始化所有的Bean 对象,而BeanFactory是需要那个才去加载那个, 因此更加轻量.(空间换时间)
2.@Service(服务存储)
使用@Service存储bean的代码如下:
@Service
public class UserService {
public void sayHi(String name) {
System.out.println("Hi"+ name);
}
}
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
//从Spring中获取UserService对象
UserService userService = context.getBean(UserService.class);
userService.sayHi("UserService");
}
运行结果:
3.@Repository(仓库存储)
使用@Repository 存储bean的代码如下所示:
@Repository
public class UserRepository {
public void sayHi() {
System.out.println("Hi,UserRepository");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
//从Spring中获取对象
UserRepository userRepository = context.getBean(UserRepository.class);
userRepository.sayHi();
}
}
运行结果:
4.@Component(组件存储)
使用@Component 存储bean的代码如下所示:
@Component
public class UserComponent {
public void sayHi() {
System.out.println("Hi,UserComponent");
}
}
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
//从Spring中获取对象
UserComponent userComponent = context.getBean(UserComponent.class);
userComponent.sayHi();
}
}
运行结果:
5.@Configuration(配置存储)
使用@Configuration存储bean的代码如下所示:
@Configuration
public class UserConfiguration {
public void sayHi() {
System.out.println("Hi, UserConfiguration");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//获取Spring上下文对象
ConfigurableApplicationContext context =
SpringApplication.run(DemoApplication.class, args);
//从Spring中获取对象
UserConfiguration userConfiguration = context.getBean(UserConfiguration.class);
userConfiguration.sayHi();
}
}
运行结果:
2)为什么要这么多注解?
这个和应用分成是呼应的.让程序员看到类注解之后,就能直接了解当前类的用途.
- @Controller: 控制层,接收请求,对请求进行处理,并进行响应.
- @Service: 业务逻辑层,处理具体的业务逻辑
- @Repository: 数据访问层,也称为持久层.负责数据访问操作
- @Configuration: 配置层,处理项目中的一些配置信息
程序的应用分层,调用流程如下:
类注解之间的关系
其实这些注解里面都有一个注解@Component , 说明它们本身就是属于@Component 的" 子类".
@Component是一个元注解,也就是说可以注解其他类注解,如 @Controller,@Serivce,@Repository等.这些注解被称为@Component的衍生注解.
@Controller,@Service和@Repository用于更具体的用例(分别在控制层,业务逻辑层,持久化层),在开发过程中,如果你要在业务逻辑层使用@Component或@Service,显然@Serivce是更好的选择
3)方法注解@Bean
类注解是添加到某个类上的,但是存在两个问题:
1.使用外部包里的类,没办法添加类注解
2.一个类,需要多个对象,比如多个数据源
这种场景,我们就需要使用方法注解@Bean
我们先来看看方法注解如何使用:
public class BeanConfig {
@Bean
public User user() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
User user = context.getBean(User.class);
System.out.println(user);
}
运行结果: 运行失败
why?
1.方法注解要配合类注解使用
在Spring框架设计中,方法注解@Bean要配合类注解才能将对象正常的存储到Spring容器中,
如下代码所示:
@Component
public class BeanConfig {
@Bean
public User user() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
运行结果:
2.定义多个对象
对于同一个类,如何定义多个对象呢?
我们看下@Bean的使用
@Component
public class BeanConfig {
@Bean
public User user1() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("lisi");
user.setAge(19);
return user;
}
}
定义了多个对象的话,我们根据类型获取兑现,获取的是哪个对象呢?
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
User user = context.getBean(User.class);
System.out.println(user);
}
运行结果:
报错信息显示: 期望只有一个匹配,结果发现了两个,user1,user2
接下来我们根据名称来获取bean对象
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
User user1 = (User) context.getBean("user1");
System.out.println(user1);
User user2 = (User) context.getBean("user2");
System.out.println(user2);
}
运行结果:
可以看到,@Bean可以针对同一个类,定义多个对象.
3.重命名Bean
可以通过设置name属性给Bean对象进行重命名操作,如下代码所示:
@Bean(name = {"u1,user1"})
public User user() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
此时我们使用u1就可以获取到User对象了,如下代码所示:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
User user = (User) context.getBean("u1");
System.out.println(user);
}
}
运行结果:
name可以省略,只有一个名称时,{}也可以省略.
原文地址:https://blog.csdn.net/2302_79392547/article/details/140566357
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!