引言
Spring 是众多开源java项⽬中的⼀员,基于分层的javaEE应⽤⼀站式轻量级开源框架,目的是简化企业应用程序的开发,主要核⼼是IOC(控制反转/依赖注⼊)与 AOP(⾯向切⾯)两⼤技术,实现项⽬在开发过程中的轻松解耦,提⾼项⽬的开发效率。在项⽬中引⼊ Spring 可以降低组件之间的耦合度,实现软件各层之间的解耦。
Spring IOC
IOC,Inversion of Control,控制反转,指将对象的控制权转移给Spring框架,由 Spring 来负责控制对象的生命周期(比如创建、销毁)和对象间的依赖关系。简单来说,原本是程序员手动通过new指令去创建对象,给属性赋值,并且管理类与类之间的关系,使用完之后还要销毁。而现在则是由IOC容器来帮忙创建对象,将所有的类登记在spring中,当需要时,不再主动去new,而是告诉Spring容器,然后Spring 就会在系统运行到适当的时机,把你想要的对象主动给你。也就是说,对于某个具体的对象而言,以前是由自己控制它所引用对象的生命周期,而在IOC中,所有的对象都被 Spring 控制,控制对象生命周期的不再是引用它的对象,而是Spring容器,由 Spring 容器帮我们创建、查找及注入依赖对象,而引用对象只是被动的接受依赖对象,所以这叫控制反转。
Bean对象实例化
Spring实例化Bean对象的方式有三种,分别是构造器实例化、静态工厂实例化、实例化工厂实例化。
1.构造器实例化(主要使用)
实现创建Bean对象UserService.java
package com.xxxx.service;
public class UserService {
public void test(){
System.out.println("UserService Test...");
}
}
设置配置文件Spring.xml
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.test();
2.静态⼯⼚实例化(了解)
定义静态工厂类
package com.xxxx.factory;
import com.xxxx.service.UserService;
/**
* 定义静态⼯⼚类
*/
public class StaticFactory {
/**
* 定义对应的静态⽅法,返回实例化对象
* @return
*/
public static UserService createUserService() {
return new UserService();
}
}
然后在配置文件中这样设置:
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.test();
3.实例化工厂实例化(了解)
定义工厂类:
package com.xxxx.factory;
import com.xxxx.service.UserService;
/**
* 定义⼯⼚类
*/
public class InstanceFactory {
/**
* 定义⽅法,返回实例化对象
* @return
*/
public UserService createUserService() {
return new UserService();
}
}
<bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory" factory-
method="createUserService"></bean>
获取实例化对象:
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.test();
SpringIOC手动装配
Spring基于xml手动注入Bean的方式共有四种,分别是:
- set()方法注入;
- 构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
- 静态工厂注入;
- 实例工厂注入;
set⽅法注⼊(推荐)
1.属性字段提供set⽅法
public class UserService {
// 业务对象UserDao set注⼊(提供set⽅法)
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
2.配置⽂件的bean标签设置property标签
<!--
IOC通过property标签⼿动装配(注⼊):
Set⽅法注⼊
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<!--业务对象 注⼊-->
<property name="userDao" ref="userDao"/>
</bean>
构造器注⼊
注:需要带参构造
XML配置:
<!--
IOC通过构造器注⼊:
通过constructor-arg标签进⾏注⼊
name:属性名称
ref:指定bean标签的id属性值
-->
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
<bean id="userService" class="com.xxxx.service.UserService">
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>
静态⼯⼚注⼊
定义静态工厂类
public class StaticFactory {
// 定义静态⽅法
public static TypeDao createTypeDao() {
return new TypeDao();
}
}
Java代码:
public class TypeService {
private TypeDao typeDao;
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test() {
System.out.println("TypeService Test...");
}
}
<!--
静态⼯⼚注⼊:
静态⼯⼚注⼊也是借助set⽅法注⼊,只是被注⼊的bean对象的实例化是通过静态⼯⼚实例化的
-->
<bean id="typeDao" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao"></bean>
实例化⼯⼚注⼊
定义⼯⼚类
public class InstanceFactory {
public TypeDao createTypeDao() {
return new TypeDao();
}
}
Java代码:
public class TypeService {
private TypeDao typeDao;
public void setTypeDao(TypeDao typeDao) {
this.typeDao = typeDao;
}
public void test() {
System.out.println("TypeService Test...");
}
}
<!--
实例化⼯⼚注⼊:
实例化⼯⼚注⼊也是借助set⽅法注⼊,只是被注⼊的bean对象的实例化是通过实例化⼯⼚实例化的
-->
<bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean>
<bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao">
</bean>
循环依赖
循环依赖问题在Spring中主要有三种情况:
(1)通过构造方法进行依赖注入时产生的循环依赖问题。
(2)通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
(3)通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
在Spring中,只有第(3)种方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。这是因为:
第一种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
第二种setter方法(多例)的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。
Spring在单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要功臣。解决的核心原理就是:在对象实例化之后,依赖注入之前,Spring提前暴露的Bean实例的引用在第三级缓存中进行存储。
Spring自动装配
1.@Resource注解实现⾃动注⼊(来自jdk根据Name和type注入,反射);2.@Autowired注解实现⾃动化注⼊(根据类型注入)
注:@Autowired和@Resource之间的区别:
(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
SpringAOP
什么是AOP?
Aspect Oriented Programing ⾯向切⾯编程,相⽐较 oop ⾯向对象编程来说,Aop关注的不再是程序代
码中某个类,某些⽅法,⽽aop考虑的更多的是⼀种⾯到⾯的切⼊,即层与层之间的⼀种切⼊,所以称
之为切⾯。
AOP的特点
1. 降低模块与模块之间的耦合度,提⾼业务代码的聚合度。(⾼内聚低耦合)
2. 提⾼了代码的复⽤性。
3. 提⾼系统的扩展性。(⾼版本兼容低版本)
4. 可以在不影响原有的功能基础上添加新的功能
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取信息的方式,对该信息进行装饰,以取代鱼油对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
代理模式
(1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
(2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。
(3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add*、search*。annotation方式可以指定被哪些注解修饰的代码进行拦截。
(4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
(5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。
(6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。
(7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
参考文献:https://blog.csdn.net/feng8403000/article/details/122277724