目录
前言
Spring基础与核心概念
Spring是什么
1、什么是容器
2、什么是IoC
3、理解SpringIoC
4、DI(依赖注入)
Spring的创建和使用
1、创建Spring项目
1.1、创建一个普通Maven项目
1.2、添加Spring框架支持
1.3、添加启动类和main方法
2、存储Bean对象
2.1、创建Bean对象
2.2、将Bean对象存储到Spring当中
3、获取并使用Bean对象
3.1、先得到Spring上下文对象
3.2、从Spring中取出Bean对象
3.3、使用Bean
Spring更简单的读取和存储对象
1、存储Bean对象
1.1、配置扫描路径
1.2、添加注解存储Bean对象
2、获取Bean对象
2.1、属性注入
2.2、构造方法注入
2.3、Setter注入
2.4、使用@Resource(另一种注入方法)实现
Bean作用域和生命周期
1、Bean作用域定义
1.1、singleton(单例作用域)
1.2、prototype(原型作用域/多例作用域)
1.3、request(请求作用域)
1.4、session(回话作用域)
1.5、applicatioon(全局作用域)
1.6、设置作用域
2、Spring执行流程和Bean的生命周期
2.1、Spring执行流程
2.2、Bean生命周期
Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。
Spring指的是Spring Framework(Spring框架),它是一个开源框架。Spring支持广泛的应用场景,它可以让java的企业级的应用程序开发起来更简单
Spring是包含了众多工具方法的IoC容器
容器是用来容纳某种物品的(基本)装置
Inversion of Control(控制反转)
传统代码
public class App {
public static void main(String[] args) {
Car car=new Car(30);
car.init();
}
}
public class Car {
private Framework framework;
public Car(int size){
framework=new Framework(size);
}
public void init(){
System.out.println("执行了car init方法");
//依赖车身
framework.init();
}
}
public class Framework {
private Bottom bottom;
public Framework(int size){
bottom=new Bottom(size);
}
public void init(){
System.out.println("执行了framework init方法");
//依赖底盘
bottom.init();
}
}
public class Bottom {
private Tire tire;
public Bottom(int size){
tire=new Tire(size);
}
public void init(){
System.out.println("执行了buttom init方法");
//依赖轮胎
tire.init();
}
}
public class Tire {
private int size=20;
public Tire(int size){
this.size=size;
}
public void init(){
System.out.println("执行了轮胎初始化方法,size:"+this.size);
}
}
改进后的代码
public class App {
public static void main(String[] args) {
Tire tire=new Tire(23);
Buttom buttom=new Buttom(tire);
FrameWork frameWork=new FrameWork(buttom);
Car car=new Car(frameWork);
car.init();
}
}
public class Car {
private FrameWork frameWork;
public Car(FrameWork frameWork){
this.frameWork=frameWork;
}
public void init(){
System.out.println("执行car");
//依赖车身
frameWork.init();
}
}
public class FrameWork {
public Buttom buttom;
public FrameWork(Buttom buttom){
this.buttom=buttom;
}
public void init(){
System.out.println("执行framework");
//依赖车底
buttom.init();
}
}
public class Buttom {
private Tire tire;
public Buttom(Tire tire){
this.tire=tire;
}
public void init(){
System.out.println("执行buttom");
//依赖轮胎
tire.init();
}
}
public class Tire {
private int size=23;
public Tire(int size){
size=this.size;
}
public void init(){
System.out.println("轮胎-size:"+size);
}
}
当最底层代码改动之后,整个调用链上的所有代码都需要修改,解决传统开发中的缺陷
Spring是一个IoC(控制反转)容器,具备两个最基础的功能:将对象存入到容器;从容器中取出对象。其最核心的功能就是如何将对象存入到Spring中,再从Spring中获取对象的过程
将对象存放到容器中的好处:将对象存储在loC容器相当于将以后可能用的所有工具制作好都放到仓库中,需要的时候直接取就行了,用完再把它放回到仓库。而new对象的方式相当于,每次需要工具了,才现做,用完就扔掉了也不会保存,下次再用的时候还得重新做,这就是IoC容器和普通程序开发的区别。
在程序运行期间,动态地将某个对象引入到当前的机制(或行为)
从广义来说:IoC(设计思想)=DI(具体的实现技术),从不同的维度来描述同一问题
Maven项目导入jar和设置国内源的方法:
配置国内源
配置和检测 setting.xml
maven项目下载jar失败的解决方案:
没有配置国内源;
删除本地仓库的所有jar包,重写下载;
网络运营商访问国内源接口出现问题
public class User {
public String exo(){
return "baekhyun";
}
}
在resources下创建一个spring配置文件
将Bean对象配置到spring配置文件中
id中是bean对象名称 class中是对象本身:包名+类名
或者
BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
User user= (User) context.getBean("user");
System.out.println(user.exo());
获取Bean的方式:
1、根据名称获取Bean
User user=(User)context.getBean(“user”)
2、根据Bean类型来获取Bean
User user=context.getBean(User.class)
3、根据Bean名称+Bean类型来获取Bean
User user=context.getBean(“user”,User.class)
ApplicationContext和BeanFactory
相同点:
1、都是可以得到Spring上下文对象;
2、都是来自Spring的顶级接口
不同点:
1、继承关系和功能方面来说: Spring容器有两个顶级的接口: BeanFactory和ApplicationContext。ApplicationContext 属于BeanFactory的子类,其中BeanFactory提供了基础的访问Bean的能力。ApplicationContext除了继承了BeanFactory 的所有功能之外,它还包含更多的功能,如国际化支持、资源访问、事件传播等。
2、从性能方面来说: ApplicationContext 是一次性加载并初始化所有的Bean对象,而BeanFactory 是需要哪个Bean才去加载Bean对象,因此更加轻量。
类注解:@Controller(控制器)、@Service(服务)、@Repository(仓库)、@Component(组件)、@Configuration(配置)
方法注解:@Bean(将当前修饰方法的方法对象存储到Spring当中)
方式一:类注解
1.2.1、@Controller(控制器存储)
@Controller
public class ArticleController {
public String sayHi(){
return "hello,controller";
}
}
ArticleController articleController=context.getBean("articleController",ArticleController.class);
System.out.println(articleController.sayHi());
1.2.2、@Component(组件)
@Component
public class UserComponent {
public String sayHi(){
return "hi,@component";
}
}
UserComponent userComponent=context.getBean("userComponent",UserComponent.class);
System.out.println(userComponent.sayHi());
项目中没有目录,所有的类都写在Java根路径下
1.2.3、@Service(服务)
@Service
public class ArticleController {
public String sayHi(){
return "hello,controller";
}
}
1.2.4、@Repository(仓库)
@Repository
public class ArticleController {
public String sayHi(){
return "hello,controller";
}
}
1.2.5、@Configuration(配置)
@Configuration
public class ArticleController {
public String sayHi(){
return "hello,controller";
}
}
五大类注解用途:
1、@Controller(控制器):归属于业务逻辑层,用来控制用户的行为,它用来检查用户参数的有效性
2、@Service(服务):归属于服务层,调用持久化类实现相应的功能(不直接和数据库交互,类似于控制中心)
3、@Repository(仓库):归属于持久层,是直接和数据库进行交互的。通常每一个表都会对应一个@Repository
4、@Configuration(配置):归属于配置层,是用来配置当前项目的一些信息
4、@Component(组件):归属于公共工具类,提供某些公共方法
调用流程如下:
方式二:方法注解
将返回的对象存储到Spring当中
注意事项:@Bean一定要配合五大类注解
public class Student {
private int id;
private String name;
private int age;
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Component
public class StudentBeans {
@Bean
public Student student(){
Student stu=new Student();
stu.setId(04);
stu.setName("baekhyun");
stu.setAge(30);
return stu;
}
}
Student student=context.getBean("student",Student.class);
System.out.println(student);
或
@Component
public class StudentBeans {
@Bean(name = {"s1","s2"})
public Student student(){
Student stu=new Student();
stu.setId(04);
stu.setName("baekhyun");
stu.setAge(30);
return stu;
}
}
Student student=context.getBean("s1",Student.class);
System.out.println(student);
当给@Bean设置了name属性之后,使用原方法名就不能获取到对象了,只能使用设置的名称才能获取
获取bean对象的过程也叫做对象装配,是把对象取出来放到某个类中,其也叫做对象注入
@Autowired
@Controller
public class StudentController {
//1、使用属性注入获取bean
@Autowired
private StudentService studentService;
public void sayHi(){
//调用service方法
studentService.sayHi();
}
}
@Service
public class StudentService {
public void sayHi(){
//
System.out.println("hi,service");
}
}
StudentController sc=context.getBean("studentController",StudentController.class);
sc.sayHi();
优点:实现简单
缺点:不能注入不可变(final)对象
只能适用于IoC容器
针对对象是类,容易违背单一设计原则
//3、构造方法注入
private StudentService studentService;
@Autowired
public StudentController(StudentService studentService){
this.studentService=studentService;
}
如果当前类中只有一个构造方法,可以省略@Autowired
优点:可以注入不可变对象;
//3、构造方法注入
private final StudentService studentService;
public StudentController(StudentService studentService){
this.studentService=studentService;
}
注入对象不会被修改(原因:加了final修饰符;构造方法是随着类加载只执行一次的,不像set有可能执行多次被修改的风险);
注入对象会被完全初始化;
通用性更好
缺点:没有属性注入实现简单
//2、set注入
private StudentService studentService;
@Autowired
public void setStudentService(StudentService studentService){
this.studentService=studentService;
}
优点:更加符合单一设计原则(针对对象方法级别)
缺点:不能注入不可变对象
注入的对象可被修改(set方法是普通set方法,可以被重复调用,在被调用时就存在修改的风险)
@Resource
private StudentService studentService;
@Resource和@Autowired
相同点:都是用来实现依赖注入的
不同点:
1、功能支持不同:@Autowired支持属性注入、setter注入、构造方法注入;@Resource支持属性注入和setter注入,但不支持构造方法注入
2、出身不同:@Autowired来自Spring框架;@Resource来自于JDK
3、参数支持不同:@Autowired只支持required参数;@Resource支持更多的参数设置
Bean在整个Spring框架(项目)中的某种行为模式
描述:该作用域下的Bean在loC容器中只存在一个实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是同一个对象
场景:通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新
备注:Spring默认选择该作用域
@Controller
public class UserController {
@Autowired
private User user1;
public void getUser(){
System.out.println("user1:"+user1);
User u=user1;
u.setName("边伯贤");
System.out.println("u:"+u);
}
}
@Controller
public class UserAdviceController {
@Resource
private User user1;
public void getUser(){
System.out.println("user1:"+user1);
}
}
@Component
public class UserBeans {
@Bean
public User user1(){
User user=new User();
user.setId(4);
user.setName("baekhyun");
user.setPassword("30");
return user;
}
}
UserController userController=context.getBean("userController",UserController.class);
userController.getUser();
UserAdviceController userAdviceController=context.getBean("userAdviceController",UserAdviceController.class);
userAdviceController.getUser();
描述:每次对该作用域下的Bean的请求都会创建新的实例:获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是新的对象实例
场景:通常有状态的Bean使用该作用域
描述:每次http请求会创建新的Bean实例,类似于prototype
场景:一次http的请求和响应的共享Bean
备注:限定SpringMVC中使用
描述:在一个http session中,定义一个Bean实例
场景:用户回话的共享Bean,比如:记录一个用户的登陆信息
备注:限定SpringMVC中使用
描述:在一个http servlet Context中,定义一个Bean实例
场景:Web应用的上下文信息,比如:记录一个应用的共享信息
备注:限定SpringMVC中使用
singleton(单例作用域)和application(全局作用域):
singleton是Spring Core的作用域,application是Spring Web中的作用域;
singleton作用于IoC的容器,application作用于Servlet容器
通过使用@Scope来设置Bean的作用域
直接设置值:@Scope("prototype")
全局变量的方式设置:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
a.启动容器(启动项目);
b.读取配置文件,初始化(使用xml直接注册bean;配置bean根路径);
c.将bean存储到spring中,通过类注解进行扫描和装配;
d.将spring从注解中读取出来,装配到相应的类
a.实例化Bean(为Bean分配内存空间)
b.设置属性(Bean的注入和装配)
c.Bean初始化
d.使用Bean
e.销毁Bean
@Component
public class BeanLifeComponent implements BeanNameAware {
@Override
public void setBeanName(String s) {
System.out.println("执行了通知");
}
@PostConstruct
public void postConstruct(){
System.out.println("执行了@PostConstruct");
}
public void init(){
System.out.println("执行了init-method方法");
}
@PreDestroy
public void PreDestory(){
System.out.println("执行了销毁方法");
}
}
public class App2 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
BeanLifeComponent beanLifeComponent=context.getBean("beanLifeComponent",BeanLifeComponent.class);
System.out.println("使用Bean");
//销毁Bean
context.destroy();
}
}
案例:如何实现A->B->C
@Component
public class AComponent {
@Autowired
private BComponent component;
@PostConstruct
public void postConstruct(){
System.out.println("执行了A对象的postConstruct方法");
}
}
@Component
public class BComponent {
@Autowired
private CComponent component;
@PostConstruct
public void postConstruct(){
System.out.println("执行了B对象的postConstruct方法");
}
}
@Component
public class CComponent {
@PostConstruct
public void postConstruct(){
System.out.println("执行了C对象的postConstruct方法");
}
}
public class App3 {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
AComponent aComponent=context.getBean("AComponent",AComponent.class);
}
}