spring核心:IOC和AOP详解

引言

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

<bean id = "userService" class = "com.xxxx.service.UserService" ></bean>
获取实例化对象:
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();
 }
}

然后在配置文件中这样设置:

<!-- 静态⼯⼚ -->
<bean id = "userService" class = "com.xxxx.factory.StaticFactory" factory-method = "createUserService" ></bean>
获取实例化对象:
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();
 }
}
设置配置⽂件 spring.xml
1.定义实例化⼯⼚bean
2.引⽤⼯⼚bean 指定⼯⼚创建⽅法(⽅法为⾮静态)
<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的方式共有四种,分别是:

  1. set()方法注入;
  2. 构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
  3. 静态工厂注入;
  4. 实例工厂注入;
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...");
 }
}
XML 配置:
<!--
 静态⼯⼚注⼊:
 静态⼯⼚注⼊也是借助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...");
 }
}
XML 配置:
<!--
 实例化⼯⼚注⼊:
 实例化⼯⼚注⼊也是借助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的技术,主要分为两大类:一是采用动态代理技术,利用截取信息的方式,对该信息进行装饰,以取代鱼油对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

代理模式

代理模式在 Java 开发中是⼀种⽐较常⻅的设计模式。设计⽬的旨在为服务类与客户类之间插⼊其他功
能,插⼊的功能对于调⽤者是透明的,起到伪装控制的作⽤。如租房的例⼦:房客、中介、房东。对应
于代理模式中即:客户类、代理类 、委托类(被代理类)。
为某⼀个对象(委托类)提供⼀个代理(代理类),⽤来控制对这个对象的访问。委托类和代理类有
⼀个共同的⽗类或⽗接⼝。代理类会对请求做预处理、过滤,将请求分配给指定对象。常用的代理模式有静态代理和动态代理两种。
代理的三要素:
a 、有共同的⾏为(结婚) - 接⼝
b 、⽬标⻆⾊(新⼈) - 实现⾏为
c 、代理⻆⾊(婚庆公司) - 实现⾏为 增强⽬标对象⾏为
静态代理的特点:
1 、⽬标⻆⾊固定
2 、在应⽤程序执⾏前就得到⽬标⻆⾊
3 、代理对象会增强⽬标对象的⾏为 4 、有可能存在多个代理 引起 " 类爆炸 " (缺点)
动态代理的两种实现⽅式:
1. JDK 动态代理
2. CGLIB 动态代理
动态代理的特点
1. ⽬标对象不固定
2. 在应⽤程序执⾏时动态创建⽬标对象
3. 代理对象会增强⽬标对象的⾏为
动态代理分为jdk动态代理和CGLIB动态代理,JDK动态代理的⽬标对象必须有接⼝实现,⽽不能实现接⼝的类就不能使⽤JDK的动态代理,cglib是针对类来实现代理的,它的原理是对指定的⽬标类⽣成⼀个⼦类,并覆盖其中⽅法实现增强,但因为采⽤的是继承,所以不能对final修饰的类进⾏代理。SpringAOP的底层设计就是动态代理(JDK+CGLIB)。
基本概念:
 

(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值