Spring学习笔记

学习内容:

  1. Spring概述
  2. Spring优点
  3. 如何使用IOC
  4. IOC底层原理
  5. IOC特性
  6. Spring的工程方法
  7. IOC的自动装载

学习笔记:

1. Spring概述

  • Spring是什么?

    • Spring是一个企业级开发框架,是软件设计层面的框架,优势在于可以将应用程序进行分层,开发者可以自主选择组件。
    • Spring已经成为Java领域的行业标准
    • Spring全家桶:
      • Web:Spring Web MVC/Spring MVC 、Spring Web Flux
      • 持久层:Spring Data/Spring Data JPA 、Spring Data Redis、 Spring Data MongoDB
      • 安全校验:Spring Security
      • 建构工程脚手架:Spring Boot
      • 微服务:Spring Cloud
  • Spring两大核心机制:

    • IOC(控制反转)/DI(依赖注入)

IOC是Spring全家桶各个功能模块的基础,是创建对象的容器

  • AOP(面向切面编程)

2. Spring的优点:

  • 低侵入式设计

使得代码污染性极低,应用程序对Spring API的依赖可以减至最小限度

  • 独立于各种应用服务器
  • 依赖注入特性将组件关系透明化,降低了耦合度。

Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器的管理,大大的降低了组件之间的耦合性。

  • 支持AOP

面向切面编程特性允许将通用任务如安全、事物、日志等进行集中式处理,从而提高了程序的复用性。

  • 与第三方框架的良好整合

Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如Struts、Hibernate、MyBatis、Quartz等)的直接支持

3.如何使用IOC

在使用之前我们需要了解什么叫做控制反转:

传统的程序开发中,需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动new出来的,而在Spring框架中创建对象的工作时不再由调用者完成,而是交由IOC容器来创建,再推送给调用者。

如何使用IOC:

  1. 创建Maven工程,pom.xml添加依赖
pom.xml
	<dependency>
 		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.0.11.RELEASE</version>
	</dependency>
	
	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-context</artifactId>
  		<version>5.0.11.RELEASE</version>
	</dependency>

  1. 创建实体类Student
Student.java
   	package com.hbb.entity;
	import lombok.Data;
	@Data
	public class Student {
		private long id;
		private String name;
		private int age;
	}
  1. 传统的开发方式,手动new
StudentTest.java
	package com.hbb.test;
	import com.hbb.entity.Student;
	public class StudentTest {
		public static void main(String[] args) {
			Student sdt = new Student();
			sdt.setId(1L);
			sdt.setAge(20);
			sdt.setName("葛小蕾");
			System.out.println(sdt);
		}
	}

此处需要导入lombok的jar包,用来简化实体类的开发
需要首先从网上下载lombok-1.18.6.jar版本,配置到pom.xml里
配置好后找到jar的本地位置,通过CMD命令执行安装。
命令:java -jar lombok-1.18.6.jar
配置好后,对于实体类,不需要再实装set/get方法和toString方法,即可直接调用。
添加方法:

pom.xml
	<!-- 简化实体类的开发 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.6</version>
      <scope>provided</scope>
    </dependency>

  1. 通过IOC创建对象,在配置文件中添加需要管理的对象,XML格式的配置文件,文件名可自定义
    关于配置文件:
  • 通过配置bean标签来完成对象管理
    • id ≈ 对象名
    • class ≈ 对象的模板类(所有交给IOC容器来管理的类必须有无参构造函数,因为Spring底层是通过反射机制来创建对象。调用的是无参构造)
    • 对象的成员变量通过property标签完成赋值
      • name:成员变量名
      • value:成员变量值(基本数据类型,String可以直接赋值,如果是其他引用类型,不能通过value赋值)
      • ref: 将IOC中的另外一个bean赋给当前的成员变量(DI)
Spring.xml(resources目录下)
	<!-- 通过ID来区分bean,名字可以自定义 -->
	<bean id="student" class="com.hbb.entity.Student">
		<property name="id" value="11"></property>
		<property name="age" value="20"></property>
		<property name="name" value="杨大宁"></property>
	</bean>

(如果有其他引用类型:)

Address.java
	public class Address {
		private long id;
		private String name;
	}

Student.java
	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	public class Student {

		private long id;
		private String name;
		private int age;
		private Address address;
	}

spring.xml
	<bean id="student" class="com.hbb.entity.Student">
		<property name="id" value="11"></property>
		<property name="age" value="20"></property>
		<property name="name" value="葛小蕾"></property>
		<property name="address" ref="address"></property>
	</bean>
	
	<bean id="address" class="com.hbb.entity.Address">
		<property name="id" value="2022"></property>
		<property name="name" value="在淮安"></property>
	</bean>

  1. 从IOC中获取对象
StudentTest.java
	// 加载配置文件
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
	Student student = (Student) applicationContext.getBean("student");
	System.out.println(student);

如果没有无参构造方法,运行时会报以下错误:
Causedby:java.lang.NoSuchMethodException:com.hbb.entity.Student.init()
补充:lombok的@AllArgsConstructor标签可用来添加有参构造方法

结果:

Student(id=11, name=葛小蕾, age=20,address=Address(id=2022, name=在淮安))

4. IOC底层原理(极简略版)

  1. 读取配置文件,解析XMl
  2. 通过反射机制实例化配置文件中所有的bean

5. IOC特性

  1. 给bean注入集合
Student.java
	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	public class Student {
		private long id;
		private String name;
		private int age;
		private List<Address> addresses;
	}

spring.xml
	<bean id="student" class="com.hbb.entity.Student">
		<property name="id" value="11"></property>
		<property name="age" value="20"></property>
		<property name="name" value="葛小蕾"></property>
		<property name="addresses">
			<list>
				<ref bean="address"></ref>
				<ref bean="address2"></ref>
			</list>
		</property>
	</bean>
	
	<bean id="address" class="com.hbb.entity.Address">
		<property name="id" value="2022"></property>
		<property name="name" value="在淮安"></property>
	</bean>
	
	<bean id="address2" class="com.hbb.entity.Address">
		<property name="id" value="2012"></property>
		<property name="name" value="世界末日之前"></property>
	</bean>

  1. scope作用域
    Spring管理的bean是根据scope来生成的,表示bean的作用域,共有四种:
  • singleton:单例,表示通过Spring容器获取的bean是唯一的
  • prototype:原型,表示通过Spring容器获取的bean是不同的
  • request:请求,表示在一次http请求有效
  • session:会话,表示在一个用户会话内有效

request和session只适用于web项目,大多数情况下,使用单例和原型较多

  • prototype模式当业务代码获取IOC容器中的bean时,Spring才去调用无参构造创建对应的bean
  • singleton模式无论业务代码是否获取IOC容器中的bean,Spring在Spring.xml时就会创建bean
  1. Spring的继承
    和Java中的继承不同,Java是类层面的继承,子类可以继承父类的内部结构信息;Spring是对象层面的继承,子对象可以继承父对象的属性值
<bean id="student2" class="com.hbb.entity.Student">
	<property name="id" value="11"></property>
	<property name="age" value="20"></property>
	<property name="name" value="葛小蕾"></property>
	<property name="addresses">
		<list>
			<ref bean="address"></ref>
			<ref bean="address2"></ref>
		</list>
	</property>
</bean>
<bean id="student3" class="com.hbb.entity.Student" parent="student2">
	<property name="name" value="小葛"></property>
</bean>

输出结果:

运行结果:
Student(id=11, name=小葛, age=20, addresses=[Address(id=2022,name=在淮安), Address(id=2012, name=世界末日之前)])

Spring的继承关注点在于重点的对象,而不在于类,即不同的两个类的实例化对象可以完成继承,前提是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他的属性

  1. Spring的依赖

和继承类似,依赖也是描述bean和bean之间的一种关系,配置依赖之后,被依赖的bean一定县创建,再创建依赖的bean,A依赖于B,先创建B,再创建A。

  1. Spring的p命名空间
    p命名空间是对IoC/DI的简化操作,使用p命名空间可以更加方便的完成bean的配置以及bean之间的依赖注入关系。
    头文件中包含:
xmlns:p=http://www.springframework.org/schema/p

通过p命名空间配置属性:

spring.xml
	<bean id="student" class="com.hbb.entity.Student" p:id="101" p:age="30" p:name="创造" p:addresses-ref="address"></bean>
	<bean id="address" class="com.hbb.entity.Address" p:id="1314" p:name="再爱你"></bean>

输出结果:

Student(id=101, name=创造, age=30, addresses=[Address(id=1314, name=再爱你)])

6.Spring的工厂方法:

IOC通过工厂模式创建bean的方法有两种:

  1. 静态工厂方法
创建实体类Cat.java

package com.hbb.Ioc;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Cat {
	private int age;
	private String name;
}

创建静态工厂类StaticCatFactory .java

package com.hbb.factory;
import java.util.HashMap;
import java.util.Map;
import com.hbb.Ioc.Cat;

public class StaticCatFactory {

	private static Map<Long, Cat> catMap;
	
	static {
		catMap = new HashMap<Long, Cat>();
		catMap.put(1L, new Cat(11, "小葛"));
		catMap.put(2L, new Cat(22, "小杨"));
	}

	public static Cat getCat(int age) {
		return catMap.get(age);
	}
}

在static静态代码块中进行catMap的实例化。在类被加载时即可被调用。

在spring.xml里配置静态工厂

	<!-- 配置静态工厂,创建cat -->
	<bean id="cat" class="com.hbb.factory.StaticCatFactory" factory-method="getCat">
		<constructor-arg value="2"></constructor-arg>
	</bean>

测试类StaticCatFactoryTest.java

package com.hbb.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hbb.Ioc.Cat;

public class StaticCatFactoryTest {

	public static void main(String[] args) {

		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
		Cat cat = (Cat) applicationContext.getBean("cat");
		System.out.println(cat);
	}

}

  1. 实例工厂方法
实例工厂类InstanceCatFactory .java

package com.hbb.factory;
import java.util.HashMap;
import java.util.Map;
import com.hbb.Ioc.Cat;

public class InstanceCatFactory {

	private static Map<Long, Cat> catMap;
	
	public InstanceCarFactory() {
		catMap = new HashMap<Long, Cat>();
		catMap.put(1L, new Cat(11, "小葛"));
		catMap.put(2L, new Cat(22, "小杨"));
	}

	public Cat getCat(int age) {
		return catMap.get(age);
	}
}

在无参构造方法中进行catMap的实例化。当实例工厂类实例化时即可被调用

在spring.xml里配置实例工厂

	<!-- 配置实例工厂bean -->
	<bean id="catFactory" class="com.hbb.factory.InstanceCatFactory">
	</bean>
	
	<!-- 配置实例工厂,创建cat -->
	<bean id="cat2" factory-bean="catFactory" factory-method="getCat">
		<constructor-arg value="1"></constructor-arg>
	</bean>

实例工厂的方式时,需要先配置实例工厂bean,和配置普通bean的方式是一样的。然后再配置实例工厂,创建car。通过factory-bean将cat2依赖于实例工厂catFactory

测试类CatFactoryTest.java

public class CatFactoryTest {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
		Cat cat = (Cat) applicationContext.getBean("cat2");
		System.out.println(cat);

	}

7. IOC的自动装载

IoC负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时Spring提供了另外一种更加简便的依赖注入方式:
自动装载——不需要手动配置property,IoC容器会自动选择bean完成注入。

自动装载有两种方式:

  • byname:通过属性名自动装载
  • byType:通过属性的数据类型自动装载
创建实体类Car.java

package com.hbb.entity;
import lombok.Data;

@Data
public class Car {
	private long id;
	private String name;
}

创建实体类Person.java

package com.hbb.entity;
import com.hbb.entity.Car;
import lombok.Data;

@Data
public class Person {
	private long id;
	private String name;
	private Car car;
}

测试类PersonTest,java

package com.hbb.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.hbb.entity.Person;

public class PersonTest {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
		Person person = (Person) applicationContext.getBean("person");
		System.out.println(person);
	}
}

byName的方式如下(autowire=“byName”):

在spring.xml中配置bean

	<bean id="car" class="com.hbb.entity.Car">
		<property name="id" value="1"></property>
		<property name="name" value="玛莎拉蒂"></property>
	</bean>
	
	<bean id="person" class="com.hbb.entity.Person" autowire="byName">
		<property name="id" value="11"></property>
		<property name="name" value="小葛"></property>
	</bean>

结果:

Person(id=11, name=小红, car=Car(id=1, name=玛莎拉蒂))

通过名字进行装载。将注入的事情交给IoC容器来完成。
IoC容器寻找名字是car的bean,找到后,自行装载给Person。
如果找不到的话,car的值是null。(不进行装载)

byType的方式(autowire=“byType”):

在spring.xml中配置bean

	<bean id="car2" class="com.hbb.entity.Car">
		<property name="id" value="1"></property>
		<property name="name" value="玛莎拉蒂"></property>
	</bean>
	
	<bean id="person" class="com.hbb.entity.Person" autowire="byType">
		<property name="id" value="11"></property>
		<property name="name" value="小葛"></property>
	</bean>

结果与byName的结果相同
byType的方式,是通过类型来进行匹配的,只要bean的类型和实体类(Person.java)中成员变量的类型(Car)是一致的,就可以进行装载。

但是使用byType会存在一个问题:
如果配置文件spring.xml里同时有两个及以上的符合条件的bean时,自动装载会抛出异常(没有唯一的bean)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值