Spring

7 minute read

控制反转 ioc 是一种解耦的设计思想。它的主要目的是借助于“第三方”(Spring 中的 IOC 容器) 实现具有依赖关系的对象之间的解耦。 Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。

举个例子:”对象a 依赖了对象 b,当对象 a 需要使用 对象 b的时候必须自己去创建。 但是当系统引入了 IOC 容器后, 对象a 和对象 b 之前就失去了直接的联系。 这个时候,当对象 a 需要使用 对象 b的时候, 我们可以指定 IOC 容器去创建一个对象b注入到对象 a 中”。 对象 a 获得依赖对象 b 的过程,由主动行为变为了被动行为,控制权翻转,这就是控制反转名字的由来。

依赖注入 di DI(Dependecy Inject,依赖注入)是实现控制反转的一种设计模式,依赖注入就是将实例变量传入到一个对象中去。

1,工厂模式

Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。

两者对比: BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于BeanFactory 来说会占用更少的内存,程序启动速度更快。 ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。

ApplicationContext的三个实现类: ClassPathXmlApplication:把上下文文件当成类路径资源。 FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。 XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

2,单例模式 Spring 中 bean 的默认作用域就是 singleton(单例)的。 除了 singleton 作用域,Spring 中 bean 还有下面几种作用域: prototype : 每次请求都会创建一个新的 bean 实例。 request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。 global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

Spring 实现单例的方式: xml : 注解:@Scope(value = “singleton”)

Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。Spring 实现单例的核心代码如下 // 通过 ConcurrentHashMap(线程安全) 实现单例注册表 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, “‘beanName’ must not be null”); synchronized (this.singletonObjects) { // 检查缓存中是否存在实例
Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //…省略了很多代码 try { singletonObject = singletonFactory.getObject(); } //…省略了很多代码 // 如果实例对象在不存在,我们注册到单例注册表中。 addSingleton(beanName, singletonObject); } return (singletonObject != NULL_OBJECT ? singletonObject : null); } } //将对象添加到单例注册表 protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));

        }
    } }

3,代理模式 Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象, 而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib

当然你也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。

静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强; 而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

4,装饰者模式 装饰者模式可以动态地给对象添加一些额外的属性或行为。相比于使用继承,装饰者模式更加灵活。 简单点儿说就是当我们需要修改原有的功能,但我们又不愿直接去修改原有的代码时,设计一个Decorator套在原有代码外面。 其实在 JDK 中就有很多地方用到了装饰者模式,比如 InputStream家族,InputStream 类下有 FileInputStream (读取文件)、BufferedInputStream (增加缓存,使读取文件速度大大提升)等子类都在不修改InputStream 代码的情况下扩展了它的功能。

Spring 中配置 DataSource 的时https://www.codercto.com/a/24209.html候,DataSource 可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下动态切换不同的数据源?这个时候就要用到装饰者模式。

5,观察者模式 Spring 事件驱动模型 Spring 事件驱动模型包括三个概念:事件、事件监听器、事件发布者。

事件 ApplicationEvent public abstract class ApplicationEvent extends EventObject { private final long timestamp; // protected transient Object source; 父类中定义 public ApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); } } 自定义事件时只需要继承ApplicationEvent

事件监听器 ApplicationListener @FunctionalInterface public interface ApplicationListener extends EventListener {

void onApplicationEvent(E event); } ApplicationListener 接口限定 ApplicationEvent的子类作为接口中方法的参数,所以每一个监听器都是针对某一具体的事件进行监听。

事件发布者 ApplicationEventPublisher @FunctionalInterface public interface ApplicationEventPublisher {

default void publishEvent(ApplicationEvent event){
    publishEvent((Object) event);
}

void publishEvent(Object event); } ApplicationContext 实现了ApplicationEventPublisher,所以发布事件时可直接通过ApplicationContext

特点 一个事件可被多个监听器监听处理 如果事件发布方法存在事务,那么事件发布和事件监听方法处于同一事务中,属于同步处理。 可通过onApplicationEvent添加@Async注解变为异步处理

注解 @EventListener 可在监听方法上使用@EventListener注解代替实现ApplicationListener接口, 并可在方法上添加@Order注解实现监听器处理的顺序 @TransactionalEventListener 可隔离事件发布和监听的事务

参考(有案例):https://juejin.cn/post/6844904033589673992

spring aop的应用场景有哪些? https://www.javazhiyin.com/67370.html 日志、打点、鉴权

aop底层原理是什么? jdk动态代理和cglib动态代理

是编译时期进行织入,还是运行期进行织入? 运行期,生成字节码,再加载到虚拟机中,JDK是利用反射原理,CGLIB使用了ASM原理,字节码增强

初始化时期织入还是获取对象时织入? 初始化的时候,已经将目标对象进行代理,放入到spring 容器中

spring AOP 默认使用jdk动态代理还是cglib? 要看条件,如果实现了接口的类,是使用jdk。如果没实现接口,就使用cglib。

spring aop和aspectJ的关系是什么? Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。

@autowired和@resource的区别是什么? @Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。 @Resource注解和@Autowired一样,也可以标注在字段或属性的setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。 @Resources按名字,是jdk的,@Autowired按类型,是spring的。

@springbootApplicaion注解的作用? @SpringBootApplication 注解等价于以同时使用 @SpringBootConfiguration,@EnableAutoConfiguration 和@ComponentScan @ComponentScan注解就是用来自动扫描被这些注解标识的类,最终生成ioc容器里的bean @SpringBootConfiguration与@Configuration作用相同,都是用来声明当前类是一个配置类 @EnableAutoConfiguration是springboot实现自动化配置的核心注解,通过这个注解把spring应用所需的bean注入容器中

Updated:

Leave a comment