IOC的简单介绍
什么是Spring?Spring是一个开源的框架,让我们的开发更加的简单,我们可以用一句更加具体的话来概括Spring,就是Spring是一个包含众多工具方法的IOC容器。
简单介绍一下IOC,我们之前说过通过@ReqestController和@Controller注解,把对象交给Spring管理,在启动Spring框架时,就会加载类交给Spring管理,这就是IOC思想。
IoC: Inversion of Control (控制反转),也就是说Spring是⼀个"控制反转"的容器。
控制反转
就是控制权反转,什么的控制权发⽣了反转? 获得依赖对象的过程被反转了 也就是说,当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊(DependencyInjection,DI)就可以了。
传统的开发思路
例如:造一辆小汽车
根据如下的代码:
public class Tire {
int size;
public Tire(Integer size){
this.size=size;
System.out.println("Tire size ="+size);
}
}
public class Bottom {
private Tire tire;
public Bottom(Integer size){
this.tire=new Tire(size);
System.out.println("bootom size"+size);
}
}
public class Framework {
private Bottom bottom;
public Framework(Integer size){
this.bottom=new Bottom(size);
System.out.println("framework size"+size);
}
}
public class Car {
private Framework framework;
public Car(Integer size){
this.framework=new Framework(size);
System.out.println("car size"+size);
}
public void run(){
System.out.println("car can run ");
}
}
public class Main {
static int size;
public static void main(String[] args) {
Car car=new Car(12);
car.run();
}
}
这样的代码维护性很低
如果我们把Tire类中构造方法的参数去掉,那么其他有关的调用程序就会报错,会连续报错一连串的错误,程序的耦合性很高,而我们写代码讲究高内聚,低耦合,所以这样的传统的开发思路已经不实用了
我们可以尝试一种新的设计思路
根据如下的代码:
public class Tire {
int size;
public Tire(Integer size){
this.size=size;
System.out.println("Tire size ="+size);
}
}
public class Bottom {
private Tire tire;
public Bottom(Tire tire){
this.tire=tire;
System.out.println("bootom size"+tire.size);
}
}
public class Framework {
private Bottom bottom;
public Framework(Bottom bottom){
this.bottom=bottom;
System.out.println("framework size");
}
}
public class Car {
private Framework framework;
public Car(Framework framework){
this.framework=framework;
System.out.println("car size");
}
public void run(){
System.out.println("car can run ");
}
}
public class Main {
static int size;
public static void main(String[] args) {
Tire tire=new Tire(12);
Bottom bottom=new Bottom(tire);
Framework framework=new Framework(bottom);
Car car=new Car(framework);
car.run();
}
}
我们只需要将原先创建的下级类,改为传递的方法,这样我们在修改或者添加一些参数时,不需要重新修改创建的下级类,下级类也不会改变,这样我们就实现了解耦。
这部分代码就是IOC容器做的事情
DI(依赖注入)
容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。(也可以说DI是IOC的一种实现)
IOC & DI的使用
Spring 容器管理的主要是对象,这些对象,我们称之为"Bean".我们把这些对象交由Spring管理,由 Spring来负责对象的创建和销毁.我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出 对象
我们可以使用@Component注解和@Autowired注解来完成这个过程
import org.springframework.stereotype.Component;+
@Component
public class Tire {
int size=12;
public Tire(){
System.out.println("Tire size ="+size);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component("/bottom4")
public class Bottom {
private Tire tire;
@Autowired
public Bottom(Tire tire){
this.tire=tire;
System.out.println("bootom size"+tire.size);
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;+
@Component
public class Framework {
private Bottom bottom;
@Autowired
public Framework(Bottom bottom){
this.bottom=bottom;
System.out.println("framework size");
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Car {
private Framework framework;
@Autowired
public Car(Framework framework){
this.framework=framework;
System.out.println("car size");
}
public void run(){
System.out.println("car can run ");
}
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
//在 Spring 框架中,Bean 是指 Spring 容器 中的一个对象。
// 简单来说,Spring 管理的任何对象都可以被称为 Bean。
// 这些对象由 Spring 容器 创建、初始化、管理,并根据需要进行生命周期管理。
@SpringBootApplication
public class Main {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Main.class, args);
// 获取 Spring 管理的 Bean
Car car = context.getBean(Car.class);
car.run();
}
}
IOC详解
bean的存储
共有两类注解类型可以实现:
类注解:@Controller @Component @Configuration @Repository @Service
方法注解:@Bean
@Controller(控制器存储)
注:记得在对象前加@Controller注解
用原始的方法获取对象其中的方法
public class HelloController {
public void print(){
System.out.println("controller");
}
}
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
//用原始的方法来获得对象及其中的方法
HelloController helloController=new HelloController();
helloController.print();
}
利用@controller来获取bean对象的三种方法
1.根据bean的名称来获取bean
@Controller("controller")
public class HelloController {
public void print(){
System.out.println("controller");
}
HelloController bean=(HelloController) context.getBean("controller");
bean.print();
2.根据bean的类型来获取bean
@Controller("controller")
public class HelloController {
public void print(){
System.out.println("controller");
}
HelloController bean2=context.getBean(HelloController.class);
bean2.print();
3.根据bean的名称和方法来获取bean
@Controller("controller")
public class HelloController {
public void print(){
System.out.println("controller");
}
HelloController bean3=context.getBean("controller",HelloController.class);
bean3.print();
运行结果:
当然还有其他的方法
注:bean的名称使用小驼峰的写法
@Service(服务储存)
利用@Service存储bean
@Service
public class UseService {
public void print(){
System.out.println("service");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseService bean6 = context.getBean(UseService.class);
bean6.print();
}
@Repository(仓库存储)
利用@Repository存储bean
@Repository
public class UseRepository {
public void print(){
System.out.println("repository");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseRepository bean7 = context.getBean(UseRepository.class);
bean7.print();
}
@Component(组件存储)
利用@Component存储bean
@Component
public class UseComponent {
public void print(){
System.out.println("component");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseComponent bean4 = context.getBean(UseComponent.class);
bean4.print();
}
@Configuration(配置存储)
利用@Configuration存储bean
@Configuration
public class UseConfiguration {
public void print(){
System.out.println("configuration");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseConfiguration bean5 = context.getBean(UseConfiguration.class);
bean5.print();
}
注解的作用
@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息.
程序的应用分层,调用方式
通过看这些注解的源码,我们发现这些注解中都有@Component注解,都是其子类
方法注解@Bean
注:方法注解要配合类注解才可以正常的存储到Spring容器中
@Component
public class StudentComponent {
@Bean
public Student stu1(){
return new Student("zs",12);
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
Student bean8 =(Student) context.getBean(Student.class);
System.out.println(bean8);
}
如果是多个对象的时候
@Component
public class StudentComponent {
@Bean
public Student stu1(){
return new Student("zs",12);
}
@Bean
public Student stu2(){
return new Student("xx",5);
}
@Bean(name={"stu4","stu5"})
public Student stu3(){
return new Student("lisi",14);
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
Student bean8 =(Student) context.getBean(Student.class);
System.out.println(bean8);
}
我们可以根据名称来获取对象
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
Student bean8 =(Student) context.getBean("stu1");
System.out.println(bean8);
}
我们也可以对Bean进行重命名
@Bean(name={"stu4","stu5"})
路径的扫描
启动类的默认扫描路径为启动类所在的包及其子类,可以在启动类中看到扫描的路径
我们可以通过 @ComponentScan 来配置启动类的扫描路径
@ComponentScan("在里面写路径,为开始项的路径,开始项的默认路径为本类的路径")
也可以使用数组的写法
例如
@ComponentScan({"com.blame.ioc.service", "com.blame.ioc.component"})
DI详解
依赖注入
1.属性注入
是@Autowired注解实现的,将UserService类和UserConfiguration注⼊到HelloController类中
@Controller("controller")
public class HelloController {
//属性的注入
@Autowired
private UseService useService;
@Autowired
private UseConfiguration useConfiguration;
public void print(){
System.out.println("controller");
useService.print();
useConfiguration.print();
}
}
@Configuration
public class UseConfiguration {
public void print(){
System.out.println("configuration");
}
}
@Service
public class UseService {
public void print(){
System.out.println("service");
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseService service=context.getBean(UseService.class);
service.print();
UserController userController=context.getBean(UserController.class);
userController.print();
}
2.构造方法注入
@Controller("controller")
public class HelloController {
//构造方法注入
private UseService useService;
private UseConfiguration useConfiguration;
public HelloController() {
}
public HelloController(UseService useService) {
this.useService = useService;
}
@Autowired
public HelloController(UseService useService, UseConfiguration useConfiguration) {
this.useService = useService;
this.useConfiguration = useConfiguration;
}
public void print(){
System.out.println("controller");
useService.print();
useConfiguration.print();
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseService service=context.getBean(UseService.class);
service.print();
UserController userController=context.getBean(UserController.class);
userController.print();
}
注:如果只要一个构造方法,在构造方法前不用加@Autowired,但是如果是多个构造方法,必须加@Autowired,否则无法识别用哪个构造方法
3.Setter注入
@Controller("controller")
public class HelloController {
//Setter方法的注入
private UseService useService;
private UseConfiguration useConfiguration;
@Autowired
public void setUseService(UseService useService) {
this.useService = useService;
}
@Autowired
public void setUseConfiguration(UseConfiguration useConfiguration) {
this.useConfiguration = useConfiguration;
}
public void print(){
System.out.println("controller");
useService.print();
useConfiguration.print();
}
}
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
UseService service=context.getBean(UseService.class);
service.print();
UserController userController=context.getBean(UserController.class);
userController.print();
}
注:在每一Setter方法前都要加@Autowired注解
当同⼀类型存在多个bean时,使⽤@Autowired会存在问题
@Component
public class StudentComponent {
@Bean
public Student stu1(){
return new Student("zs",12);
}
@Bean
public Student stu2(){
return new Student("xx",5);
}
@Bean(name={"stu4","stu5"})
public Student stu3(){
return new Student("lisi",14);
}
}
@Controller
public class UserController {
@Autowired
private Student stu;
public void print(){
System.out.println("UserController");
System.out.println();
}
}
就会报错,错误信息为不是唯一的bean
并且给你解决的方法,使用@Primary注解或者@Qualifier注解
@Primary
使⽤@Primary注解:当存在多个相同类型的Bean注⼊时,加上@Primary注解,来确定默认的实现
@Component
public class StudentComponent {
@Primary
@Bean
public Student stu1(){
return new Student("zs",12);
}
@Bean
public Student stu2(){
return new Student("xx",5);
}
@Bean(name={"stu4","stu5"})
public Student stu3(){
return new Student("lisi",14);
}
}
@Qualifier
使⽤@Qualifier注解:指定当前要注⼊的bean对象。
注:@Qualifier注解不能单独使用,必须配合@Autowired注解使用。
@Controller
public class UserController {
@Qualifier("stu1")
@Autowired
private Student stu;
public void print(){
System.out.println("UserController");
System.out.println();
}
}
@Resource
使用@Resource注解也可以解决这个问题
@Controller
public class UserController {
@Resource(name = "stu1")
private Student stu;
public void print(){
System.out.println("UserController");
System.out.println();
}
}
@Autowird与@Resource的区别
1.@Autowird是按类型注入,而@Resource是按名称进行注入。
2.@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
总结一下吧!
简单说一下Spring, Spring Boot和SpringMVC的关系以及区别
Spring 是基础框架,Spring MVC 是 Spring 提供的一种 Web 开发方式(模块),Spring Boot 是简化 Spring 应用开发和部署的工具和框架(整合+自动配置)
我们可以把这三者的关系比作开一家餐厅
Spring就是这家餐厅的基础设施:桌子,椅子,电,水,人员管理。
Spring MVC就是这家餐厅的点餐系统和前台的服务人员。
Spring Boot就相当于这个餐厅的加盟系统,任何东西都给你提供好了,你只需要做菜和开门营业就行了。
希望能对大家有所帮助!!!