spring IOC和AOP的底层实现
spring IOC和AOP的底层实现
https://juejin.im/post/5bf51d4c5188256d9832b0d3
IOC
2、spring核心主要两部分:
(1)aop:面向切面编程:扩展功能不是修改源代码实现
(2)Ioc:控制反转,比如有一个类,在类里面有方法(不是静态的方法,创建类的对象,使用对象调用方法,创建类对象的过程,需要new出来对象。
现在对象的创建不是通过new方式实现,而是交给spring配置创建对象)
1、创建对象
(1)直接new
public class User{
public void add(){
…
}
}
//在servlet调用User类里面的方法
User user =new User();
user.add()
缺点:如果类名改了,servlet里面也要跟着改。总之,两个类之间耦合度太强。
(2)使用工厂方法
降低了Servlet和service的耦合,但servlet和工厂又产生了耦合
(3)Spring IOC
配置文件
类里面的实现
public class UserService{
public void add(){}
}
public class UserServlet{
private UserServlet userServlet;
public void UserService(UserServlet UserServlet){
this.userServlet=userServlet;
}
}
这样,userServlet就可以直接调用UserService类里面的方法啦
2、IOC底层原理使用技术
(1)xml配置文件
(2)dom4j解析xml文件
(3)工厂设计模式
(4)反射
那么这几种技术是怎么用到IOC里面的呢?
第一步:创建xml配置文件,配置要创建对象类
第二步:创建工厂类,使用dom4j解析配置文件+反射
如果类的路径或类名发生了变化,只需更改配置文件即可,降低了类之间的耦合度。
总体上说,IOC 是一种可以帮助我们解耦各业务对象间依赖关系的对象绑定方式,那么Spring 提供了两种容器类型来提供支持 IOC方式。这两种类型是:
- BeanFactory: 基础类型的IOC容器,提供完整的IOC服务支持
- ApplicationContext: ApplicationContext是在 BeanFactory的基础之上构建的,是相对高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext提供了其他高级特性。
BeanFactory
BeanFactory的介绍
BeanFactory 是基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入工作。
BeanFactory,就是生产 Java Bean 的工厂,作为Spring 提供的基本的IoC容器,BeanFactory 帮助完成 业务对象的注册和对象间依赖关系的绑定。
实际上,BeanFactory只是一个接口,它负责定义如何访问容器内管理的Bean的方法,各个BeanFactory的具体实现类负责具体Bean的注册以及管理工作。
从上图可以看出,BeanFactory有三个直接子类:
- ListableBeanFactory: 通过继承该接口可以列出所有的Bean,也可以只列出与预期类型相对应的bean
- HierarchicalBeanFactory: 支持分层bean的管理,使BeanFactory支持双亲IOC容器的管理功能
- AutowireCapableBeanFactory: 可以填充不受Spring 控制的 Bean
ApplicationContext
ApplicationContext的介绍
ApplicationContext是在BeanFactory的基础上构建的,是相对比较高级的容器实现,除了拥有 BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如:
- 统一资源加载策略
- 国际化信息支持
- 容器内部事件发布机制
在ApplicationContext 容器启动之后,默认全部初始化并绑定完成,所以,对于BeanFactory来说,ApplicationContext 往往要求更多的系统资源
对象注入方式
我们都知道IOC容器一般有两种对象注入方式:基于XML配置文件 与 基于注解驱动的方式。下面就分别从这两个角度来看如何使用 ApplicationContext
基于 XML 配置文件
- 定义个实体类
public class User {
private Integer id;
private String username;
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
- 设置一个XML配置文件,声明 User Bean
<?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="user" class="com.pjmike.spring.domain.User">
<constructor-arg name="id" value="1"/>
<constructor-arg name="username" value="pjmike"/>
</bean>
</beans>
基于注解方式
- 声明一个配置类
@Configuration
public class UserConfiguration {
@Bean(name = "user")
public User user() {
User user = new User();
user.setUsername("pj");
return user;
}
}
从上面的两个例子可以看出基于XML和基于注解注入Bean 的方式是不一样的,基于XML的应用上下文ClassPathXmlApplicationContext
需要设置配置路径,基于注解的应用上下文AnnotationConfigApplicationContext
需要注册一个配置Bean,但它们相同的一步就是必须要调用 refresh()
方法,该方法可以看做是IOC容器的启动方法,它会做很多操作,比如完成配置的解析、各种BeanFactoryPostProcessor和BeanPostProcessor的注册、国际化配置的初始化、web内置容器的构造等等,不调用它,容器就无法启动。这里只是简要说明,更加详细的介绍会在后面的文章介绍。
现在是springboot盛行的阶段,基于XML配置文件的方式已经逐步被基于注解的方式所取代,如今的项目中,更多的使用 注解的方式。
AOP
https://juejin.im/post/591d8c8ba22b9d00585007dd
例如,我们会对API进行抽象成四个模块:Controller,Service,Gateway,Command.这很好地解决了业务级别的开发,但对于系统级别的开发我们很难聚焦。比如、对于每一个模块需要进行打日志、代码监控、异常处理。以打日志为例,我只能将日志代码嵌套在各个对象上,而无法关注日志本身,而这种现象又偏离了OOP思想。
为了能够更好地将系统级别的代码抽离出来,去掉与对象的耦合,就产生了面向AOP(面向切面)。如上图所示,OOP属于一种横向扩展,AOP是一种纵向扩展。AOP依托于OOP,进一步将系统级别的代码抽象出来,进行纵向排列,实现低耦合。
1.2 AOP 的家庭成员
1.2.1 PointCut
即在哪个地方进行切入,它可以指定某一个点,也可以指定多个点。
比如类A的methord函数,当然一般的AOP与语言(AOL)会采用多用方式来定义PointCut,比如说利用正则表达式,可以同时指定多个类的多个函数。
1.2.2 Advice
在切入点干什么,指定在PointCut地方做什么事情(增强),打日志、执行缓存、处理异常等等。
1.2.3 Advisor/Aspect
PointCut + Advice 形成了切面Aspect,这个概念本身即代表切面的所有元素。但到这一地步并不是完整的,因为还不知道如何将切面植入到代码中,解决此问题的技术就是PROXY
1.2.4 Proxy
Proxy 即代理,其不能算做AOP的家庭成员,更相当于一个管理部门,它管理 了AOP的如何融入OOP。之所以将其放在这里,是因为Aspect虽然是面向切面核心思想的重要组成部分,但其思想的践行者却是Proxy,也是实现AOP的难点与核心据在。
AOP的技术实现Proxy
AOP仅仅是一种思想,那为了让这种思想发光,必然脱离语言本身的技术支持,Java在实现该技术时就是采用的代理Proxy,那我们就去了解一下,如何通过代理实现面向切面