Spring框架

spring图标

Spring框架

企业级开发框架、软件设计层框架、可将应用分层、开发者自主选择组件

Spring框架核心机制

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

AOP(面向切面编程)

IOC(控制反转)

这里我们来举个例子、就好比我们有个A类、B类、当我们想使用B类时、通常做法是直接就new一个B类对象、而IOC就是提供了一个容器、我们不需要直接new一个B类对象、而是直接去容器里面取B类对象即可

IOC

使用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.dream.xiaobo</groupId>
<artifactId>spring1</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<!-- Spring上下文依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.11.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!-- 自动生成set和get方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
<scope>provided</scope>
</dependency>

</dependencies>
</project>
1
2
3
4
5
6
7
8
@Data
public class Student {

private Integer id;
private String name;
private Integer age;

}
  • 传统方式
1
2
3
4
5
Student student = new Student();
student.setId(1);
student.setName("小博");
student.setAge(21);
System.out.println(student);
  • IOC方式
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- 配置要管理的对象-->
<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="id" value="1"/>
<property name="name" value="小博"/>
<property name="age" value="20"/>
</bean>

</beans>
1
2
3
ApplicationContext application = new ClassPathXmlApplicationContext("spring.xml");
Student student = (Student)application.getBean("student");
System.out.println(student);

IOC文件配置

id:对象名
class:对象模板类(此类必须有无参构造函数、因为Spring通过反射机制创建对象、调用无参构造函数)
name:成员变量
value:成员变量值(基本数据类型、String)
ref:将IOC中另一个Bean赋值给当前成员变量

1
2
3
4
5
6
7
8
9
10
11
<!--    配置要管理的对象-->
<bean id="person" class="com.dream.xiaobo.entity.Person">
<property name="id" value="1"/>
<property name="name" value="小博"/>
<property name="age" value="21"/>
<property name="student" ref="student" />
</bean>
<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="name" value="xiaobo" />
<property name="sex" value="男" />
</bean>

IOC 底层原理模拟

1
2
3
4
5
6
7
8
9
10
11
@Data//set和get方法
@AllArgsConstructor//有参构造(所有参数)
@NoArgsConstructor//无参构造
public class Person {

private Integer id;
private String name;
private Integer age;
private Student student;

}
1
2
3
4
5
public interface ApplicationContext {

public Object getBean(String id);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public class ClassPathXmlApplicationContext implements ApplicationContext {

Map<String,Object> ioc = new HashMap<String, Object>();

public ClassPathXmlApplicationContext(String path){


try {
//拿到spring.xml配置文件
SAXReader reader = new SAXReader();
Document document = reader.read("./src/main/resources/" + path);

//拿到spring.xml配置文件上下文
Element root = document.getRootElement();

//获得迭代器
Iterator<Element> element = root.elementIterator();
//遍历beans
while (element.hasNext()){
Element next = element.next();
//获得id
String id = next.attributeValue("id");
//获得class
String className = next.attributeValue("class");

//通过反射拿到class
Class clazz = Class.forName(className);
//拿到无参构造
Constructor constructor = clazz.getConstructor();
//创建无参构造的对象
Object object = constructor.newInstance();
//获得迭代器
Iterator<Element> iterator = next.elementIterator();
//遍历bean
while (iterator.hasNext()){
Element el = iterator.next();
//拿到name
String name = el.attributeValue("name");
//拿到value
String valueStr = el.attributeValue("value");
//拿到ref
String ref = el.attributeValue("ref");
//判断ref
if(ref == null){
//将name转换为set方法
String s = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
//获取本身属性
Field field = clazz.getDeclaredField(name);
//获取方法
Method method = clazz.getDeclaredMethod(s, field.getType());

Object value = null;
if(field.getType().getName() == "java.lang.Integer"){
value = Integer.valueOf(valueStr);
}
if(field.getType().getName() == "java.lang.String"){
value = valueStr;
}
//执行方法
method.invoke(object,value);
}
ioc.put(id,object);
}
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}

}


public Object getBean(String id) {
return ioc.get(id);
}
}
1
2
3
4
5
6
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);

}

通过运行是类获取Bean

1
2
3
ApplicationContext application = new ClassPathXmlApplicationContext("spring.xml");
Person person = (Person)application.getBean(Person.class);
System.out.println(person);

通过有参构造赋值

1
2
3
4
5
<!--    通过有参构造赋值-->
<bean>
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="xiaobo"/>
<constructor-arg name="age" value="21"/>
1
2
3
4
5
6
<!--    通过有参构造赋值-->
<bean>
<constructor-arg index="0" value="3"/>
<constructor-arg index="1" value="wyb"/>
<constructor-arg index="2" value="21"/>
</bean>

Bean注入集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<bean id="person" class="com.dream.xiaobo.entity.Person">
<property name="id" value="1"/>
<property name="name" value="小博"/>
<property name="age" value="21"/>
<property name="students">
<list>
<ref bean="student"></ref>
<ref bean="student2"></ref>
</list>
</property>
</bean>

<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="name" value="xiaobo" />
<property name="sex" value="男" />
</bean>
<bean id="student2" class="com.dream.xiaobo.entity.Student">
<property name="name" value="r" />
<property name="sex" value="女"/>
</bean>

scope作用域

spring管理bean的作用域是靠scope控制的、共4种、默认值是singleton

  • singleton 单例
1
<bean name="student" class="com.dream.xiaobo.entity.Student" scope="singleton"/>
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

Student student1 = (Student)applicationContext.getBean("student");
Student student2 = (Student)applicationContext.getBean("student");
Student student3 = (Student)applicationContext.getBean("student");

System.out.println(student1 == student2);//true
System.out.println(student1 == student3);//true
System.out.println(student2 == student3);//true
}

由结果可得出、singleton通过IOC容器获得的Bean是唯一的、并且当spring.xml被加载时bean就被创建

  • prototype 原型
1
<bean name="student" class="com.dream.xiaobo.entity.Student" scope="prototype"/>
1
2
3
4
5
6
7
8
9
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

Student student1 = (Student)applicationContext.getBean("student");
Student student2 = (Student)applicationContext.getBean("student");
Student student3 = (Student)applicationContext.getBean("student");

System.out.println(student1 == student2);//false
System.out.println(student1 == student3);//false
System.out.println(student2 == student3);//false

由结果可得出、prototype通过IOC容器获得的Bean是不同的、并且当业务获取IOC容器中bean时才被创建

  • request 请求

在一次HTTP请求内有效

  • session 会话

在一次用户会话内有效

Bean之间继承

子对象可以继承父对象的属性值、子对象必须包含父对象的所有属性、并且可以在父对象的基础上自行添加

1
2
3
4
5
<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="name" value="xiaobo" />
<property name="sex" value="男" />
</bean>
<bean name="user" class="com.dream.xiaobo.entity.User" parent="student"></bean>

Bean之间依赖

被依赖的Bean先创建、在创建依赖的Bean、A依赖B、在创建B、在创建A

1
<bean name="user" class="com.dream.xiaobo.entity.User" depends-on="student"></bean>

工厂方法

  • 静态工厂方法
1
2
3
4
<!--    静态Bean-->
<bean id="car" class="com.dream.xiaobo.factory.StaticCarFactory" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class StaticCarFactory {

static Map<Long, Car> map = null;

static{

map = new HashMap<Long, Car>();
map.put(1L,new Car(1,"摩托车"));
map.put(2L,new Car(2,"赛车"));

}

public static Car getCar(Long id){
return map.get(id);
}

}
  • 实例工厂方法
1
2
3
4
5
<!--实例Bean-->
<bean id="instance" class="com.dream.xiaobo.factory.InstanceCarFactory"/>
<bean id="car2" factory-bean="instance" factory-method="getCar">
<constructor-arg value="2"></constructor-arg>
</bean>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ublic class InstanceCarFactory {

Map<Long, Car> map = null;

public InstanceCarFactory(){
map = new HashMap<Long, Car>();
map.put(1L,new Car(1,"摩托车"));
map.put(2L,new Car(2,"赛车"));
}

public Car getCar(Long id){
return map.get(id);
}
}

IOC自动装载(Autowire)

  • 自动装载byName方式

通过属性名自动装载

1
2
3
4
5
6
7
8
<bean id="person" class="com.dream.xiaobo.entity.Person" autowire="byName">
<property name="id" value="1"/>
<property name="name" value="xiaobo"/>
<property name="age" value="21"/>
</bean>
<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="name" value="wang"/>
<property name="sex" value="男"/>
  • 自动装载byType方式

通过属性的数据类型自动装载、类型不能出现相同的否则报错

1
2
3
4
5
6
7
8
9
<bean id="person" class="com.dream.xiaobo.entity.Person" autowire="byType">
<property name="id" value="1"/>
<property name="name" value="xiaobo"/>
<property name="age" value="21"/>
</bean>
<bean id="student" class="com.dream.xiaobo.entity.Student">
<property name="name" value="wang"/>
<property name="sex" value="男"/>
</bean>

AOP(面向切面)

动态的将代码切入到类指定的位置、将不同的方法的同一位置抽象成一个切面对象、然后对这个切面进行编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
public class CalImpl implements Cal {

public double add(int a, int b) {
double result = a + b;
return result;
}

public double sub(int a, int b) {
double result = a - b;
return result;
}

public double mul(int a, int b) {
double result = a * b;
return result;
}

public double div(int a, int b) {
double result = a / b;
return result;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Aspect//定义切面类
@Component//将该类注入到IOC容器中
public class LoggerAspect {

@Before(value = "execution(public double com.dream.xiaobo.aop.impl.CalImpl.*(..))")
public void before(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
String args = Arrays.toString(joinPoint.getArgs());
System.out.println(name + "的方法参数是" + args);
}

//
@After(value = "execution(public double com.dream.xiaobo.aop.impl.CalImpl.*(..))")
public void after(JoinPoint joinPoint){
String name = joinPoint.getSignature().getName();
System.out.println(name + "方法执行完毕");
}

@AfterReturning(value = "execution(public double com.dream.xiaobo.aop.impl.CalImpl.*(..))",returning = "result")
public void afterRetrun(JoinPoint joinPoint,Object result){
String name = joinPoint.getSignature().getName();
System.out.println(name + "方法的结果是:" + result);
}

@AfterThrowing(value = "execution(public double com.dream.xiaobo.aop.impl.CalImpl.*(..))",throwing = "exception")
public void afterThread(JoinPoint joinPoint,Exception exception){
String name = joinPoint.getSignature().getName();
System.out.println(name + "方法的异常:" + exception);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!-- 自动扫描、扫描该包下的交给我容器处理的所有类-->
<context:component-scan base-package="com.dream.xiaobo.aop"/>

<!-- 使Aspect注解生效、为目标类生成代理对象-->
<aop:aspectj-autoproxy/>
</beans>
1
2
3
4
5
6
7
8
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
Cal calImpl = (Cal)applicationContext.getBean("calImpl");
calImpl.add(4,2);
calImpl.sub(4,2);
calImpl.mul(4,2);
calImpl.div(4,0);
}
  • @Aspect

定义该类为切面类

  • @Component

将类注入到IOC容器

  • @Before @After

切入方法执行的具体位置和时机

  • context:component-scan

对包中所有类进行扫描、如果该类被注入到容器中了、则使用IOC管理这个类

  • aop:aspectj-auoproxy

使@Aspect标注过的类自动生成动态代理对象

切⾯:横切关注点被模块化的抽象对象
通知:切⾯面对象完成的⼯工作
目标:被通知的对象,即被横切的对象
代理:切⾯面、通知、⽬目标混合之后的对象
连接点:通知要插入业务代码的具体位置
切点:AOP 通过切点定位到连接点

正确的开始、微小的长进、然后持续、嘿、我是小博、带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:Spring框架

文章作者:小博

发布时间:2021年07月02日 - 10:15

最后更新:2021年07月02日 - 10:20

原始链接:https://codexiaobo.github.io/posts/1658389689/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。