❣博主主页: 33的博客❣
▶️文章专栏分类:JavaEE◀️
🚚我的代码仓库: 33的代码仓库🚚
🫵🫵🫵关注我带你了解更多进阶知识
目录
1.前言
2.Spring是什么?
通过前⾯的学习,我们知道了Spring是⼀个开源框架,他让我们的开发更加简单.他⽀持⼴泛的应⽤场景,有着活跃⽽庞⼤的社区,这也是Spring能够⻓久不衰的原因.但是这个概念相对来说,还是⽐较抽象.我们⽤⼀句更具体的话来概括Spring,那就是**:Spring是包含了众多⼯具⽅法的IoC容器**
IOCDI_11">3.IOC&DI入门
IOC_12">3.1IOC
那么IOC是什么呢?IOC是Spring的一种思想,其实IoC我们在前⾯已经使⽤了,我们在前⾯讲到,在类上⾯添加@RestController 和@Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交给Spring管理,就是IoC思想。IOC(Inversion of Control (控制反转))就是把控制权交给Spring管理。
例如当我们设计汽车的时候,但汽车需要车身:
java"> public class NewCarExample {public static void main(String[] args) {Car car = new Car();car.run();}}
// 汽车对象static class Car {private Framework framework;public Car() {framework = new Framework();System.out.println("Car init....");}public void run(){System.out.println("Car run...");}}
//车身对象static class Framework {private String color;public Tire(){this. color= "red";System.out.println("颜色:" +color );}}}
但这样设计,如果我想修改颜色或者是构造方法,那么整个程序都会改动。那么我们就把创建子类的方式改为注入传递。
java"> public static void main(String[] args) {Framework framework = new Framework("blue");Car car = new Car(framework);car.run();}static class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;System.out.println("Car init....");}public void run() {System.out.println("Car run...");}
}
static class Framework {private String color;public Framework(String color){this. color= color;System.out.println("颜色:" +color );}}}
代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。
DI_72">3.2DI
DI: DependencyInjection(依赖注入)容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注入。程序运⾏时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注入(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引入IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。
DI_75">3.3IoC&DI使用
我们把Framework,和car交给Spring管理,那么我们只需要使用注解 :@Component,当需要使用的时候注入依赖,使用注解: @Autowired
java">public class CarController {@Autowiredprivate Car car;public CarController(){car.run;}
}
//汽车@Componentstatic class Car {@Autowiredprivate Framework framework;public void run() {System.out.println("Car run...");}
}
//车身
@Component
static class Framework {private String color;public Framework() {this.color = "red";System.out.println("颜色:" + color);}public Framework(String color){this. color= color;System.out.println("颜色:" +color );}}}
4.Ioc实现
类注解:@Controller、@Service、@Repository、@Component、@Configuration.
⽅法注解:@Bean.
4.1@Controller
java"> @Controller//一般用于注解controller
public class UserController {public void sayHi(){System.out.println("hi,UserController...");}}
4.2 @Service
java">@Service
public class UserService {public void doService(){System.out.println("do Service....");}
}
4.3@Repository
java">@Repository
public class UserRepository {public void doRespository(){System.out.println("do Respository...");}
}
4.4@Configuration
java">@Configuration
public class UserConfiguration {public void doConfiguration(){System.out.println("do Configuration...");}
}
4.5@Component
java">public class UserComponent {public void doComponent(){System.out.println("do component...");}
}
4.6类注解区别
@Controller:控制层,接收请求,对请求进⾏处理,并进⾏响应.
@Servie:业务逻辑层,处理具体的业务逻辑.
@Repository:数据访问层,也称为持久层.负责数据访问操作
@Configuration:配置层.处理项⽬中的⼀些配置信息
当我们去看源码时,会发现@Service、@Repository、@Configuration.中都包含@Component说明这些注解本身属于@Component的“子类”。
但@Controller注解比较特殊,当我们一个类中又url接口时,只能使用@Controller,其他四个一般清空下可以混用。
4.7@Bean
类注解是添加到某个类上的,但是存在两个问题:使⽤外部包⾥的类, 没办法添加类注解
⼀个类,需要多个对象,⽐如多个数据源这种场景, 我们就需要使⽤⽅法注解@Bean,在Spring框架的设计中,⽅法注解@Bean 要配合类注解才能将对象正常的存储到Spring容器中.
java">public class User {String name;public User(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}
java">@Configuration
public class UserInfo {@Beanpublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}
5.Bean的获取
5.1通过类型获取
既然已经把 UserController交给了Spring管理,那么如何获取呢?
从上下文对象中获取:
java">//获取Spring上下问对象ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio//根据类型获取对象UserController userController = context.getBean(UserController.class);//通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();
5.2Bean的名称
除了通过类型获取,也可以通过名称获取,那么Bean的名称是说明呢?我们先来看一看官网的介绍:
类注解命名约定:
1.bean名称以⼩写字⺟开头,然后使⽤驼峰式⼤⼩写
例如:
类名:UserController, Bean的名称为:userController
类名:AccountManager,Bean的名称为: accountManager
2.有⼀些特殊情况,当有多个字符并且第⼀个和第⼆个字符都是⼤写时,将保留原始的⼤⼩写
类名:UController, Bean的名称为:UController
类名:AManager,Bean的名称为: AManage
方法注解命名约定:
方法名就是bean的名称
5.3通过名称获取
java">ApplicationContext context = SpringApplication.run(SpringIocDemoApplicatio
//通过名字获取bean
UserController userController = (UserController) context.getBean("userController");
//通过类型+名字
UserController userController = (UserController) context.getBean("userController",UserController.class);
userController.sayHi();
5.4结果
我们发现方法调用成功,但当我们打印引用地址的时候发现地址一样
那么就说明调用的是同一个对象,通过源码我们可以知道获取bean对象是父类BeanFactory提供的功能。
ApplicationContext VS BeanFactory(常⻅⾯试题)
继承关系和功能方面来说:Spring容器有两个顶级的接⼝:BeanFactory和
ApplicationContext。其中BeanFactory提供了基础的访问容器的能⼒,⽽
ApplicationContext 属于 BeanFactory 的⼦类,它除了继承了BeanFactory的所有功能之外,它还拥有独特的特性,还添加了对国际化⽀持、资源访问⽀持、以及事件传播等方面的支持.
从性能方面来说:ApplicationContext是⼀次性加载并初始化所有的Bean对象,⽽BeanFactory 是需要那个才去加载那个,因此更加轻量。
DI_246">6.DI实现
上面我们讲解了IOC实现的具体内容,接下来讲DI事项的内容,DI其实就是一个依赖注入的过程,简单来说就是把对象取出来放在某个类的属性中。
Spring给我们提供了三种方式注入:
1.属性注⼊(FieldInjection)
2. 构造⽅法注⼊(ConstructorInjection)
3. Setter 注⼊(SetterInjection)
6.1属性注入
就是使用@Autowired 实现的,将Service类注⼊到Controller类中。 Service 类的实现代码如下:
java">@Controllerpublic class UserController { @Autowiredprivate UserService userService;public void sayHi(){System.out.println("hi,UserController...");userService.sayHi();}}
6.2 构造方法注入
java">@Controllerpublic class UserController2 {private UserService userService;@Autowiredpublic UserController2(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController2...");userService.sayHi();}}
注意
如果一个类只有一个构造方法,那么@Autowired 可以省略,如果一个类有多个构造方法默认使用无参的构造方法,那么此时需要添加@Autowired 来明确指定到底使⽤哪个构造⽅法。
6.3 Setter注入
java">@Controller
public class UserController3 {
private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}public void sayHi(){System.out.println("hi,UserController3...");userService.sayHi();}}
6.4三种注入优缺点
属性注⼊
优点:简洁,使⽤⽅便;
缺点:只能⽤于IoC容器,如果是⾮IoC容器不可⽤,并且只有在使⽤的时候才会出现NPE(空指针异常)
不能注⼊⼀个Final修饰的属性
构造函数注入(Spring4.X推荐)
优点:可以注⼊final修饰的属性
注⼊的对象不会被修改
依赖对象在使⽤前⼀定会被完全初始化,因为依赖是在类的构造⽅法中执⾏的,⽽构造⽅法是在类加载阶段就会执⾏的⽅法.
通⽤性好,构造⽅法是JDK⽀持的,所以更换任何框架,他都是适⽤的
缺点:注入多个对象时,代码会⽐较繁琐
Setter注⼊(Spring3.X推荐)
优点:⽅便在类实例之后,重新对该对象进⾏配置或者注⼊
缺点:不能注入⼀个Final修饰的属性
注⼊对象可能会被改变,因为setter方法可能会被多次调用,就有被修改的风险.
6.5@Autowired问题
当一个类型存在多个对象时,使用@Autowired就会存在问题,例如:
java">@Configuration
public class UserInfo {@Beanpublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}
@Autowired
private User Uers;
public void sayhi(){System.out.println("hi,UserController");System.out.println(Uers);}
出现错误:
报错原因,非唯一的bean对象。那么如何解决呢?可以使用@Primary、@Qualifier、@Resource注解。
当有多个相同类型的对象时,用@Primary可以确定默认的实现:
java">@Configuration
public class UserInfo {@Bean@Primarypublic User user(){return new User("张三");}@Bean User user2(){return new User("李四");}
}
使⽤@Qualifier注解:指定当前要注⼊的bean对象。在@Qualifier的value属性中,指定注⼊的bean的名称。
@Qualifier注解不能单独使⽤,必须配合@Autowired使⽤
java">@Autowired@Qualifier("user2")private User Uers;public void sayhi(){service.doService();System.out.println("hi,UserController");System.out.println(Uers);}
使⽤@Resource注解:是按照bean的名称进⾏注⼊。通过name属性指定要注⼊的bean的名称。
java"> @Resource(name = "user2")private User Uers;public void sayhi(){service.doService();System.out.println("hi,UserController");System.out.println(Uers);}
注入顺序:
@Autowired执行流程:
按照类型查找:
如果没有找到就抛出异常
如果查找到一个就直接插入,
如果找到多个就根据名称查找,找到就注入,没有找到就抛出异常
@Qualifier+@Autowired执行流程:
直接按照类型+名称查找
如果@Autowired对应的类型只有一个,但是名称和@Qualifier名称不一样,注入也是失败的
@Autowird与@Resource的区别
@Autowired是spring框架提供的注解,⽽@Resource是JDK提供的注解
@Autowired默认是按照类型注⼊,⽽@Resource是按照名称注⼊.相⽐于@Autowired 来说@Resource ⽀持更多的参数设置,例如name设置,根据名称获取Bean。
7.总结
Spring, Spring Boot和SpringMVC的关系以及区别
Spring: 简单来说,Spring是⼀个开发应⽤框架,什么样的框架呢,有这么⼏个标签:轻量级、⼀站式、模块化,其⽬的是⽤于简化企业级应⽤程序开发.
Spring的主要功能:管理对象,以及对象之间的依赖关系,⾯向切⾯编程,数据库事务管理,数据访问,web框架⽀持等.但是Spring具备⾼度可开放性,并不强制依赖Spring,开发者可以⾃由选择Spring的部分或者全部,Spring可以⽆缝继承第三⽅框架,⽐如数据访问框架(Hibernate、JPA),web框架(如Struts、JSF)
Spring MVC:SpringMVC是Spring的⼀个⼦框架,Spring诞⽣之后,⼤家觉得很好⽤,于是按照MVC模式设计了⼀个MVC框架(⼀些⽤Spring解耦的组件),主要⽤于开发WEB应⽤和⽹络接⼝,所以Spring MVC是⼀个Web框架. Spring MVC基于Spring进⾏开发的,天⽣的与Spring框架集成.可以让我们更简洁的进⾏Web层开发,⽀持灵活的URL到⻚⾯控制器的映射,提供了强⼤的约定⼤于配置的契约式编程⽀持,⾮常容易与其他视图框架集成,如Velocity、FreeMarker等。
Spring Boot: Spring Boot是对Spring的⼀个封装,为了简化Spring应⽤的开发⽽出现的,中⼩型企业,没有成本研究⾃⼰的框架,使⽤SpringBoot可以更加快速的搭建框架,降级开发成本,让开发⼈员更加专注于Spring应⽤的开发,⽽⽆需过多关注XML的配置和⼀些底层的实现。Spring Boot 是个脚⼿架,插拔式搭建项⽬,可以快速的集成其他框架进来.⽐如想使⽤SpringBoot开发Web项⽬,只需要引⼊SpringMVC框架即可,Web开发的⼯作是SpringMVC完成的,⽽不是SpringBoot,想完成数据访问,只需要引⼊Mybatis框架即可.Spring Boot只是辅助简化项⽬开发的,让开发变得更加简单,甚⾄不需要额外的web服务器,直接⽣成jar包执⾏即可.
最后⼀句话总结:SpringMVC和SpringBoot都属于Spring,SpringMVC是基于Spring的⼀个MVC框架,⽽SpringBoot是基于Spring的⼀套快速开发整合包
下期预告:Spring Boot配置文件