Spring IOCDI————(1)
1,IOC&DI讲解
1,Spring是啥
Spring就是一个开源框架,他们让我们开发变得更加简单,简单来说,Spring就是一个包含了众多工具方法的IOC容器。那么啥是容器呢,我们之前学习的集合,数据结构那块就是容器,用来存储数据容器,这里也是一样,比如Tomcat就是一个Web容器;
2,啥是IOC
那么什么是IOC呢,我们其实在此之前已经使用过了,大家有没有发现,之前在RequestMapping下的代码是一个对象吧,我们调用它里面的方法实现调用功能,但是有个问题啊,我们从来都没new过对象,是不是,从来都没有,但是我们还是可以调用,这个因为这个RequestController和Controller注解中有IOC注解,就是会把这个类交给Spring管理,交给Spring管理,Spring就会帮我们来实例化对象,就是完全交给Spring;IOC简单来说就是Spring提供的存功能;
IOC带来的好处:
1,资源集中管理:IOC容器会帮我们管理一些资源,比如对象,我们在使用的时候,直接过去取就完了;
2,降低代码耦合度,创建实例的时候不用去关心实例的细节;
3,啥是DI
DI的英文翻译为中文的意思就是依赖注入,这是啥意思呢,刚才说了IOC是存,那么DI就是取,
我们可以通过一些列注解来取到我们需要的Bean,Bean就是对象;
3,Spring,Spring MVC,Spring SpringBoot关系:
三者的关系呢:
1,Spring Boot是基于Spring,Spring Boot是基于Spring框架的封装,简化了配置和部署
2,Spring MVC属于Spring,Spring MVC是Spring的Web模块,Spring Boot默认集成MVC
3,Spring Boot整合Spring全家桶,Spring Boot 可以整合 Spring MVC、Spring Data、Spring Security 等模块。
2,IOC详解
IOC即控制反转,我们想掌握IOC就是掌握IOC容器的创建和Bean的存储;
Bean的存储提供了两类注解:
1,类注解@Controller,@Service,@Repository,@Component,@Configuration
2,方法注解
@Bean
1,类注解
1,@Controller控制器存储
@Controller
public class UserController {public void sayHello(){System.out.println("Hello,Controller");}
}
使用注解就说明吧这个类给Spring管理了,
@SpringBootApplication
public class JavaTest2025519Application {public static void main(String[] args) {//或缺上下文对象ApplicationContext context = SpringApplication.run(JavaTest2025519Application.class, args);//从上下文中或缺对象UserController userController = context.getBean(UserController.class);//使用对象userController.sayHello();}}
我们可以直接获得到UserController、大家有没有唤醒一些记忆,这个.class怎么那么熟悉呢,这不反射的类加载嘛~,还有这个上下文,大家从哪听过呢,线程那,大家还有记忆没有,这里的上下文呢,指的是当前的运行环境,可以看做容器,容器存储了很多东西,就是运行环境,
我们看看有没有打印出来:
获取成功了,我们成功获取了一个对象,我们这个对象是根据类型创建的,这里我们还没指定Bean,如果有多个Bean呢,我们可能会在注入的时候进行操作,我们在获取这也能操作,我们还提供了其他的getbean方法,这个ApplicationContext继承了BeanFactory的功能,这里常用的三种方法:
1,getBean(类型)
2,getBean(Sting name)
3,getBean(String name,类型)
来试试:
UserController userController = context.getBean(UserController.class);//使用对象userController.sayHello();UserController userController1 = (UserController) context.getBean("userController");userController1.sayHello();UserController userController2 = context.getBean("userController", UserController.class);userController2.sayHello();
三种方法,打印结果:
这里注意这个String就是以小驼峰命名的类名,如果前两个名字都是大写就不动,就一个大写就改成小驼峰的命名规则,我们还没说多个bean的情况呢,具体体现在哪呢,先提前剧透一下,
我们会使用getBean的(String,类型)来获取到类,String对应的就是bean起的名字,不懂没关系,一会儿会讲解bean;
@Controller
@Data
public class UserController2 {private String name;private Integer age;public void sayHello(){System.out.println("Hello,Controller2");}public void say(){System.out.println(name+age);}@Bean("hei1")public UserController2 hei1(){UserController2 userController2 = new UserController2();userController2.setAge(18);userController2.setName("zhangsan");return userController2;}@Bean("hei2")public UserController2 hei2(){UserController2 userController2 = new UserController2();userController2.setAge(19);userController2.setName("zhangsan");return userController2;}
}
UserController2 userController3 = context.getBean("hei1", UserController2.class);userController3.say();UserController2 userController4 = context.getBean("hei2", UserController2.class);userController4.say();
看打印结果:
所以结论嗷,就是我们给Spring的类,Spring会把每个类都起一个名字,根据名称来获取对应的对象,所以是不能重名的;
我们会根据Spring中的bean来对应对象的,比如我们前三个都是UserController用的是一个类型创获取的三个对象,Spring内部创建的,所以地址应该是想同的,后面两个是UserController2中的两个bean,所以地址应该是不同的,我们来试试:
System.out.println(userController);System.out.println(userController1);System.out.println(userController2);;System.out.println(userController3==userController4);
ok,下面来个面试题,
ApplicationContext和BeanFactory
1,获取Bean是beanFactory提供的功能
2,BeanFactory提供了基础访问容器的功能,ApplicationContext是BeanFactory的子类,继承了BeanFactory之外还提供了国际化支持,资源访问支持,事件传播支持,
3,从性能方面,Application更高效,会一次加载并初始化所有的Bean,而BeanFactoty是需要哪个才加载哪个,更加轻量化,有点像单例模式的懒汉和饿汉模式;
2,@Service(服务存储)
@Service
public class UserService {public void sayHello(){System.out.println("Hello,I'm Service");}
}
UserService userService = context.getBean(UserService.class);userService.sayHello();
3,@Repository(仓库存储)
@Repository
public class UserRepository {public void sayHello(){System.out.println("Hello,I'm Repository");}
}
UserRepository userRepository = context.getBean(UserRepository.class);userRepository.sayHello();
4,@Component(组件存储)
@Component
public class UserComponent {public void sayHello(){System.out.println("Hello,I'm Component");}
}
UserComponent userComponent = context.getBean(UserComponent.class);userComponent.sayHello();
5,@Configuration(配置存储)
@Configuration
public class UserConfiguration {public void sayHello(){System.out.println("Hello,I'm Configuration");}
}
UserConfiguration userConfiguration = context.getBean(UserConfiguration.class);userConfiguration.sayHello();
2,为啥要这么多类注解
整这么多注解嘎哈呀,其实他们没有太大区别的,除了@Controller,@Controller可以返回视图大家还记得不,其他的就在语义上有区别,我们是可以进行替换的,但是还是推荐按标准来;这些注解都是@Component的子类;
@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息.
3,方法注解
类注解是写在类上的,但是嗷,存在两个问题
1,使用外部包的类是没办法添加类注解的
2,一个类,有多个对象
1,定义一个对象
@Data
public class User {private String name;private Integer age;
}
先来一个User,
@Component
public class UserController3 {@Beanpublic User get(){User user = new User();user.setName("yaoyu");user.setAge(78);return user;}
}
新的控制器,我们想拿到这个User,直接获取想要的对象
User user = context.getBean(User.class);System.out.println(user);
2,定义多个对象
@Component
public class UserController3 {@Beanpublic User get(){User user = new User();user.setName("yaoyu");user.setAge(78);return user;}@Beanpublic User get2(){User user = new User();user.setName("张三");user.setAge(18);return user;}
}
那么接下来如何应对呢,我们后面注入的时候有更好的方法,现在我们可以通过GetBean方法来输入方法名来区分比如get和get2,
User user1 = context.getBean("get",User.class);System.out.println(user1);User user2 = context.getBean("get2",User.class);System.out.println(user2);
3,重命名Bean
我们还可以给Bean起名字:
@Bean("h1")public User get3(){User user = new User();user.setName("yaoyu21212");user.setAge(78123123);return user;}@Bean("h2")public User get4(){User user = new User();user.setName("张三123");user.setAge(18123123);return user;
User user3 = context.getBean("h1",User.class);System.out.println(user3);User user4 = context.getBean("get3",User.class);System.out.println(user4);
我们看看这个是我们起的名字生效呢,还方法名生效呢, 没有类名为get3,看来还是自定义的名的优先级比较高一点;
User user3 = context.getBean("h1",User.class);System.out.println(user3);User user5 = context.getBean("h2",User.class);System.out.println(user5);
这下Bean就讲解完了;
4,扫描路径
我们的默认扫描路径就是Application同级以及以下的路径为扫描路径,我们也是可以修改的,使用@ComponentScan({"com.example.demo"})注解,里面是修改的路径,这么说的话如果被那5个类注解修饰的Bean注解也是不一定完全生效的,这是因为可能没配置扫描路径,如果在扫描路径外,那就白忙活了;