目录
目录
二十一、Spring AOP 和 AspectJ AOP 有什么区别?(A)
十二、静态代理和动态代理的区别(A)
1.实现方式:
- 静态代理需手动编写代理类,在程序运行前存在。
- 动态代理在程序运行时动态生成,有基于接口的 JDK 动态代理和基于类的 CGLIB 动态代理。
2.灵活性:
- 静态代理灵活性低,接口变化需改代码且功能相对固定。
- 动态代理灵活性高,可根据不同条件在运行时调整。
3.性能:
- 静态代理性能较好,无动态生成开销。
- 动态代理有一定性能开销,CGLIB 动态代理性能通常比 JDK 动态代理好一些。
十三、Spring 怎么使用动态代理(A)
Spring AOP 基于动态代理实现:
- 如果被代理的对象,已经实现某个接口,则SpringAOP会使用JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和 Proxy 类);
- 如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy去进行代理了,这时候Spring AOP 会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是 MethodInterceptor接口和Enhancer类);
- (Spring Aop是运行时增强)
十四、Spring框架中的Bean的作用域(A)
- singleton: Spring 只会为该 bean 对象只会创建唯一实例,Spring 中的bean默认都是单例;
- prototype :每次获取 bean,Spring 会创建一个新的bean 实例;
- request: 每一次 HTTP 请求,Spring 会创建一个新的bean 实例;
- session : 不同的 HTTP 会话,Spring 会创建不同的bean 实例;
通过XML方式设置bean的作用域
<bean id="demoDaoBean" class="com.apesource.dao.DemoDA0Impl" scope="singleton"/>
通过注解方式设置bean的作用域
@Scope(ConfigurableBeanFactory.SCOPE PROTOTYPE)
public class DemoDA0Impl implements IDemoDA0{ }
十五、Spring 框架中的Bean的线程安全
1.对于prototype作用域的 Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
2.对于 singleton 作用域的 Bean,所有的线程都共享一个单例状态的 Bean,存在资源竞争,因此是存在线程安全问题的。
3.解决办法:
对于 singleton 作用域的单例 bean,它的线程安全问题,常见有两种解决办法:
- 在 bean 中尽量避免定义可变的成员变量(用于保存数据的成员变量)
- 在类中定义一个 ThreadLocal 成员变量,将需要可变的成员变量保存在ThreadLocal中
十六、Spring 框架中的Bean生命周期(A)
1. Spring Bean 的生命周期总体分四个阶段: 实例化=>属性注入 =>初始化 =>销毁
Step1 实例化 Bean:根据配置文件中 Bean 的定义,利用 Java Reflection 反射技术创建 Bean 的实例
Step2 注入对象依赖的属性值(或对象)
Step3 处理各种Aware接口: Spring 会检测该 Bean 是否实现了 xxxAware 接口,通过 Aware 类型的接口,可以让Spring框架为当前 Bean 注入相应的内容。
- 如果 Bean 实现 BeanNameAware 接口,会调用它实现的 setBeanName(string beanId)方法,注入 Bean 的名字;
- 如果 Bean 实现 BeanclassLoaderAware 接口,调用 setBeanclassLoader()方法,注入lassLoader 对象的实例;
- 如果 Bean 实现 BeanFactoryAware 接口,会调用它实现的 setBeanFactory()方法,注入的是 Spring 工厂;
- 如果 Bean 实现 ApplicationContextAware 接口,会调用 setApplicationContext()方法,注入 Spring 上下文;
Step4 执行BeanPostProcessor前置处理:如果想对 Bean 进行一些自定义的前置处理,那么可以让 Bean 实现了 BeanPostProcessor 接口,将会在该阶段调用 postProcessBeforeInitialization(object obj,string s)方法。
Step5 执行InitializingBean初始化方法:如果 Bean 实现了 InitializingBean 接口,执行afeterPropertiesset()方法。
Step6 执行init-method自定义初始化方法:如果 Bean 在 Spring 配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
Step7 执行BeanPostProcessor后置处理:如果这个 Bean 实现了BeanPostProcessor接口,将会调用 postProcessAfterInitialization(0biect obi,string s)方法,由干这个方法是在 Bean 初始化结束后调用;
以上几个步骤完成后,已经被正确创建,可以正常使用这Bean了
Step8 执行DisposableBean销毁Bean:当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用其实现的 destroy()方法执行销毁;
Step9 执行destroy-method自定义销毁方法: 如果这个 Bean 的 spring 配置中配置了 destroy-method 属性,会自动调用其配置的自定义销毁方法。
十七、Spring 框架如何解决循环依赖?(A)
循环依赖问题是指:类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。
例如: A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题;
解决:Spring 框架解决循环依赖主要通过三级缓存来实现。
三级缓存分别是:
- 一级缓存:singletonObjects,用于存放完全创建好的单例 Bean 实例。
- 二级缓存:earlySingletonObjects,存放早期暴露的 Bean 实例(未完成属性注入)。
- 三级缓存:singletonFactories,存放可以生成早期 Bean 实例的工厂对象。
解决过程如下:
当创建一个 Bean 时,首先会在一级缓存中查找,如果未找到则开始创建。在创建过程中,如果发现存在循环依赖,会尝试从二级缓存和三级缓存中获取早期的 Bean 实例或者通过工厂对象来创建早期实例以解决依赖。例如,有 A 和 B 两个 Bean 相互依赖。当创建 A 时,发现需要 B,此时 B 还未完全创建好,但是其早期实例或者工厂对象可能已经在二级或三级缓存中,从而能够满足 A 的依赖,解决循环依赖问题。
通过这种方式,Spring 框架有效地处理了循环依赖的情况,保证了 Bean 的正常创建和依赖注入。
十八、Spring 框架中有哪些注解?(A)
1.用于声明 Bean 的注解:
@Component:定义通用Bean的注解,可标注任意类为 Bean 。如果一个 Bean 不知道属于哪个层,可以使用 @component 注解标注。
@Repository:定义数据访问层Bean的注解
@service:定义业务层Bean的注解
@Controller:定义控制器Bean的注解用于注入的注解;
2.按类型自动注入:
@Autowired:按类型自动创建
@Qualifier:按名称自动注入
声明配置、扫描、启用特性的注解;
@Configuration:声明配置类
@Componentscan:组件扫描
@EnableScheduling :启用任务调度
@EnableAspectJAutoProxy:启用自动代理工厂
十九、Spring 框架中用到的设计模式(A)
1.·工厂模式:Spring 使用工厂模式,通过 BeanFactory或 Applicationcontext 来创建对象
2.单例模式:Bean 默认作用域为单例,按照单例设计模式进行设计实现;
3.策略模式:Resource 的实现类,针对不同的资源文件,实现了不同方式的资源获取策略;
4.代理模式:Spring 的 AOP 的实现依靠动态代理(JDK的反射和CGLIB)
5.模板方法:Spring 提供了 JdbcTemplate,RedisTemplate 等模板对象,将相同的操作步骤进行了封装;
6.适配器模式:Spring A0P 的增强或通知(Advice)使用到了适配器模式,Spring MVC中也用到了适配器模式适配 Controller;
二十、Spring 框架中AOP的基本理解(A)
记忆关键字:AOP名词解释,AOP实现原理(动态代理)
1.A0P(Aspect-0riented Programming:面向切面编程):(定义)将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理、权限控制等)封装抽取成一个可重用的模块,这个模块被命名为“切面”( Aspect );(优点)便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性;
2.Spring AOP 基于动态代理实现:
- 如果被代理的对象,已经实现某个接口,则SpringAOP会使用JDK Proxy(反射),基于接口的方式,创建代理对象(JDK动态代理的核心是InvocationHandler接口和 Proxy 类);
- 如果被代理的对象,没有实现某个接口,就无法使用JDK Proxy去进行代理了,这时候Spring AOP 会使用Cglib,基于继承的方式,生成一个被代理对象的子类来作为代理(Cglib动态代理的核心是 MethodInterceptor接口和Enhancer类);
二十一、Spring AOP 和 AspectJ AOP 有什么区别?(A)
关键字:增强方式的差异(运行时、编译时),实现方式的差异(动态代理、字节码操作)
1.SpringAOP已经集成了AspectJ,AspectJ是一个Java 技术生态系统中实现 AOP 编程思想的独立框架; AspectJ相比于SpringAOP功能更加强大,但是 SpringAOP相对来说更简单更容易;
2.SpringAOP属于运行时增强,而 AspectJ是编译时增强;
3.SpringAOP基于动态代理(Proxying),而AspectJ基于字节码操作( Bytecode Manipulation );