谈谈spring ioc的理解
- IOC就是控制反转,指创建对象的控制权转移给spring,并由spring根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能复用
- DI和IOC是同一个概念的不同角度的描述,即应用程序在运行时依赖ioc容器来动态注入对象需要的外部依赖
- IOC反转了依赖关系的满足方式,将由程序员实例new的工作,交给spring
- Spring的IOC有三种注入方法:构造器注入、setter
谈谈spring aop的理解
aop被称为面向切面,作为面向对象的一种补充,用于将与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中重复代码,减低了模块间的耦合度,提高系统的可维护性。用于对权限认证、日志、事务处理
AOP实现的关键在于代理模式,aop代理主要分为静态代理(AspectJ)和动态代理(Spring AOP)
AspectJ是静态代理,也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到 java字节码中,运行的时候就是增强之后的AOP对象
Spring AOP使用的动态代理,就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象 的全部方法,并且在特殊的切点做了增强处理,并回调原对象的方法
AOP核心概念:
- Advice:通知、建议,在Spring中通过定义Advice来定义代理逻辑
- Pointcut:切点,表示Advice对应的代理逻辑应用在哪个类、哪个方法上
- Advisor:Advice+Pointcut,表示逻辑和切点的整体,可以定义封装Advisor定义切点和代理逻辑
- Weaving:织入,将Advice代理逻辑在在源代码级别嵌入到切点的过程
- Target:目标对象,被代理对象,在AOP生成的代理对象中会持有目标对象
- Join Point:连接点,在Spring AOP中就是方法的执行点
AOP的工作原理:
- Spring生成bean对象时,先实例化出来一个对象,也就是target对象
- 在堆target对象进行属性填充
- 在“初始化后”步骤中,会判断target对象有没有对应的切面
- 如果有切面,表示当前target对象需要进行AOP
- 通过Cglib或JDK动态代理机制生成一个代理对象,作为最终的bean对象
- 代理对象中有一个target属性指向了target对象
spring aop中名词解释
- 连接点(Join point):程序运行过程中所执行的方法,在Spring AOP中,一个连接点总代表一个方法的执行
- 切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。
- Aspect切面可以看成Pointcut切面和Advice通知的结合,一个界面可以由多个切点和通知组成
- 切点(Pointcut):切点用于定义要对哪些join point进行拦截
- 通知(Advice):指要在join point上执行的动作,即增强的逻辑,比如权限校验、日志记录等
- 类型有:Around、Before、After、After returning、After throwing
- 目标对象(Target):包含连接点的对象,也称为被Advice的对象。由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象
- 织入(Weaving):通过动态代理,在target的方法中执行增强逻辑的过程
- 引用(Introduction):添加额外的方法或字段到被通知的类,Spring运行引入新的接口(以及对应的实现)到如何被代理的对象。
- 例如:你可以使用一个引入来的bean实现IsModifed接口,以便简化缓存机制
spring通知有哪些
- Around环绕通知:包围一个连接点,在调用方法前后完成定义行为
- before前置通知:在连接点执行之前调用
- after后置通知:在连接点结束之前调用(不管正常还是异常)
- after returning返回通知:在正常完成后执行通知(抛异常不执行)
- after throwing异常通知:在抛异常退出时调用
spring中通知执行顺序
```xml 没有异常情况下执行顺序: around before 环绕通知前 before 前置通知 target method 执行方法 around after 环绕通知后 after 后置通知 after returning 返回通知
有异常情况下执行顺序: around before 环绕通知前 before 前置通知 target method 执行方法 around after 环绕通知后 after 后置通知 after throwing 异常通知 java.lang.RuntimeException 异常发生
<a name="koc3i"></a>
## BeanFactory和ApplicationContext
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以作为Spring的容器
1. BeanFactory是Spring里面最底层的接口,是IOC的和兴,定义了IOC的基本功能
1. 包含Bean的定义、加载、实例化、依赖注入和生命周期管理
2. BeanFactory采用的是延迟加载形式注入Bean,只有在使用某个bean时(调用getBean),才对该Bean进行加载实例化。
1. 因此也不能提前发现Spring是否存在配置问题,某个Bean属性没有注入,只有调用getBean方法时才会抛异常
1. ApplicationContext接口作为BeanFactory的子接口,包含BeanFactory功能外,还提供更完整的框架功能<br />b. 继承MessageSource,支持国际化<br />c. 资源文件访问,URL和文件(ResourceLoader)<br />d. 载入多个上下文,使得每一个上下文都专注一个特定的层次,比如应用的web层<br />e. 提供在监听器中注册bean的事件
1. ApplicationContext它是在容器启动时,一次性创建了所有的bean。这样在容器启动是,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
1. ApplicationContext启动后预载了所有的单实例Bean,所以在运行时速度比较快,因为它们已经提前创建好了,相对于BeanFactory,ApplicationContext唯一的不足之处是占用内存空间,当应用程序配置bean较多时程序启动较慢
3. ApplicationContext继承的接口:
1. EnvironmentCapable:表示拥有获取环境变量的功能
1. 可以通过ApplicationContext获取操作系统环境和JVM环境变量
2. ListableBeanFactory:表示拥有获取所有BeanNames、判断beanName是否存在BeanDefinition对象
1. 统计BeanDefinition个数、获取某个类型所对于的beanName等功能
3. HierarchicalBeanFactory:表示拥有层级关系的Bean工厂,拥有parentBeanFactory属性
1. 当BeanFactory中不存在对应的bean,这会访问其parentBeanFactory尝试获取Bean对象
4. MessageSource:表示拥有国际化功能
1. 可以直接利用MessageSource获取某个国际化资源(不同国家语言符号)
5. ApplicationEventPublisher:表示拥有事件发布功能,可以发布事件
1. ApplicationContext相对于BeanFactory比较突出常用的功能
6. ResourcePatternResolver:表示拥有加载并获取资源的功能
1. 资源可以是文件、图片等某个URL资源
<a name="U8dfh"></a>
## Spring Bean的生命周期
1. 实例化Bean
1. 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个未初始化的依赖时,容器就会调用createBean进行实例化
1. 对于ApplicationContxt容器,当容器已启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean
2. 设置对象属性(注入依赖)
1. 实例化后的对象封装到BeanWrapper对象中,Spring工具BeanDefinition中的信息,以及通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入
3. 处理Aware接口
1. Spring会检测该对象是否实现`xxxAware`接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源
1. Bean实现BeanNameAware接口会调用它实现`setBeanName(String beanId)`方法,传入bean的名字
1. Bean实现BeanClassLoaderAware接口,调用setBeanClassLoader()方法,转入ClassLoader
1. Bean实现BeanFactoryAware接口,调用setBeanFactory()方,传传递Spring工厂自身
1. Bean实现了ApplicationContextAware接口,会调用serApplicationContext(ApplicationContext)方法,传入Spring上下文
4. BeanPostProcessor前置处理
1. 对bean进行一些自定义的前置处理,可以让bean实现BeanPostProcessor接口,调用
1. `POSTProcessBeforeInitialization(Object obj, String str)`方法
5. InitializingBean
1. 如果bean实现了InitializationBean方法,执行`afeterPropertiesSet()`方法
6. init-method
1. 如果bean在spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法
7. BeanPostProcessor后置处理
1. 如果bean实现BeanPostProcessor接口,将会调用
1. `postProcessAfterInitialization(Object obj, String str)`
1. 由于这个方法是在bean初始化结束时调用的,所以可以被应用于内存或缓存技术
8. DisposableBean
1. 当bean不再需要时,会经过处理阶段,如果bean实现了DisposableBean这个接口,会被调用destroy()方法
9. destroy-method
1. Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法
<a name="uioe1"></a>
## spring bean的作用域有哪些
1. singleton:默认作用域,单例bean,每个容器一种只有一个bean实例
1. prototype:为每个bean请求创建一个实例
1. request:为每个request请求创建一个实例,在请求完成后,bean会失效并被垃圾回收器收回
1. session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例
1. global:全局作用域,所有会话共享一个实例,如果想要声明让所有会话共享的存储变量的会话,那么这个变量需要存储在global-session中
<a name="eD0EG"></a>
## spring框架中bean是线程安全的吗
Spring容器本身并没有提供bean的线程安全策略,因此可以说spring容器中bean本身不具备线程安全的特征,具体情况要结合bean的作用域来说
1. 对于prototype作用域的bean,每次都创建一个新对象,也就不存在线程安全问题
1. 对于singleton作用域的bean,所有线程共享一个单例实例的bean,存在安全问题
1. 但如果单例bean是一个无状态bean,在线程操作中bean不做查询以外的操作,线程是安全的
1. 有状态bean(Stateful Bean)有实例变量的对象,可以保存数据,非安全bean
1. 无状态bean(Stateless Bean)没有实例变量,不能保存数据,是不变类,是线程安全的
1. 有状态bean(Model和Viiew)需要自行保存线程安全可以将bean作用域由"singleton"改为"prototype"
3. 可以采用ThreadLocal解决线程安全问题,每个线程提供一个独立的变量副本,不同线程操作自己的副本
3. ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题
1. 同步机制采用"时间换空间"的方式,不同线程访问前需要获得锁
1. ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离多个线程对数据访问冲突
<a name="kabTb"></a>
## spring自动装配模式有哪些
在spring中,使用autowire来配置自动装配模式,对于无需自己查找或创建其关联的其他对象,由容器负责把想要相互协助的对象引用赋予每个对象。
1. 在Spring框架xml配置中有5种自动配置
1. no:默认方式,不进行自动装配,通过手工设置ref属性来进行装配bean
1. byName:通过bean名字进行自动装配,bean的property和另一个bean name名字相同
1. byType:通过参数的数据类型自动装配
1. constructor:通过函数进行自动装配,并且
1. autodetect
<a name="bKRJV"></a>
## BeanDefinition是什么?
> BeanDefinition表示Bean定义,
> Spring根据BeanDefinition来创建Bean对象,
> BeanDefinition有很多的属性来描述Bean
> BeanDefinition是Spring中非常核心的概念
BeanDefinition中重要的属性有
- BeanClass:BeanClass表示bean的类型,比如UserService.class、OrderService.class
- Spring在创建Bean的过程中会根据此属性来实例化得到对象
- scope:
- 表示一个Bean的作用域,比如
- scope为singleton,该bean就是一个单例Bean
- scope为prototype,该bean就是一个原型bean
- isLazy:
- 表示一个bean是不是需要懒加载,原型bean的isLazy属性不起作用
- 懒加载的单例bean,会在第一次getBean的时候生成改bean
- 非懒加载的单例bean,会在spring启动过程中直接生成好
- dependsOn:
- 表示一个bean在创建之前所依赖的其他bean,在这个bean创建之间,它所依赖的这些bean得先全部创建好
- primary:
- 表示一个bean的主bean,在spring中一个类型可以有多个bean对象
- 在进行依赖注入时,如果根据类型找到了多个bean,此时会判断这个bean中是否存在一个主bean
- 如果存在,则直接将这个主bean注入给属性
- initMethodName
- 一个bean的初始化方法,一个bean的生命周期过程中有一个步骤叫初始化方法,spring会在这个步骤去调用bean的初始化方法,初始化逻辑由程序员自己控制,表示程序员可以自定义逻辑对bean进行加工
- `@Component``@Bean``<bean/>`会解析为BeanDefinition
<a name="ueE6z"></a>
## BeanFactory
BeanFactory(Bean工厂)是一种“Spring容器”<br />它可以用来创建Bean、获取bean、是Spring中非常核心的一种组件<br />BeanFactory利用BeanDefinition来生成Bean对象<br />BeanFactory的核心子接口和实现类
- ListableBeanFacctory
- ConfigurableBeanFactory
- AutowireCapableBeanFactory
- AbstractBeanFactory
- DefaultListableBeanFactory
- 支持单例Bean、Bean别名、父子BeanFactory、Bean类型转换
- 支持Bean后置处理、FactoryBean、自动装配等等
<a name="CvqDc"></a>
## Bean生命周期
Bean生命周期是描述Spring中一个Bean创建到销毁过程中经历的步骤,其中Bean创建过程是重点<br />程序员可以利用bean生命周期对bean进行自定义加工<br />Bean生命周期创建的六个过程
1. BeanDefinition——Bean的定义
1. 它定义了某个bean的类型,Spring就是利用BeanDefinition来创建bean的
1. 比如需要利用BeanDefinition中的beanClass属性确定Bean的类型,从而实例化出对象
2. 推断构造方法——选出一个构造方法
1. 一个bean有多个构造方法,此时需要spring判断到底使用哪个构造方法
3. 实例化——构造方法反射获得对象
1. 通过构造方法反射得到一个实例化对象,在Spring中,通过BeanPostProcessor机制对实例化进行干预
4. 属性填充——给属性进行自动填充
1. 实例化获得的对象是“不完整“对象,就是没有为该对象进行属性填充(自动注入、注入依赖)
5. 初始化——对其他属性赋值、校验
1. 属性填充后,此时可以利用Spring的初始化机制对Bean进行自定义加工
1. 比如利用InitializingBean接口来对Bean中的属性进行赋值,或对Bean中的属性进行校验
6. 初始化后——AOP、生成代理对象
1. 初始化后的Bean才是真正的Bean对象,AOP机制就是在这通过BeanPostProcessor机制实现的
<a name="XsAiT"></a>
## 注册一个Bean有哪些方法
1. @Component
1. @Bean
1. @Import
1. BeanDefinitionRegistryPostProcessor
1. FactoryBean
1. applicationContext.registerBean()
1. applicationContext.register()
1. applicationContext.registerBeanDefinition()
<a name="fF1al"></a>
## @Autowired是什么
- @Autowired表示某个属性是否需要进行依赖注入,可以写在属性和方法上
- 注解中的required属性默认为true,表示没有对象可以注入给属性会抛异常
- @Autowired在Bean声明周期过程中的“属性填充”
- 会基于实例化出来的对象,对该对象进行@Autowired的属性自动给属性赋值
- Spring会根据属性类型去Spring容器中找出该类型所有的Bean对象
- 如果有多个,再根据属性名进行确认一个
- 如果required为true,并且没有找到就会抛异常
<a name="DgbZq"></a>
## @Autowired、@Reference、@Resource注入的区别
- 1. 由来
- @Autowired是Spring提供的`org.springframework.beans.factory.annotation.Autowired`
- @Reference是Java(j2ee)层面提供的`javax.annotation.Resource`
- @Resource是Dubbo提供的 `dubbo.config.annotation.Reference`
- 2. 用法
- Autowired和Reference注解注入的是本地Spring容器的对象
- Reference注解一般注入的是分布式的远程服务对象,需要配置dubbo使用
- 3.注入方式
- @Autowired按照bytype自动注入,如果有多个会按照同名寻找
- 属性:required默认true (当没有找到时会报错)
- 在字段上会注入到字段中(不支持静态字段)
- 在方法上会注入到局部参数中,并执行方法
- 当Component的类有多个构造器会指定构造器(默认使用无参,没有无参多个有参会报错)**用不到**
- @Resource默认按byName自动注入,如果有多个再根据byType
- @Resource有两个重要的属性name和type
- 同时指定name和type会查找唯一匹配的bean,找不到抛异常
- 指定name会从查找名字(id)匹配的bean,找不到抛异常
- 指定type会寻找唯一的bean,找不到或多个会抛异常
- 都没指定会自动按照byName进行装配,没有匹配会退回原始类型
<a name="CcQaj"></a>
## @param是什么?
<a name="VNzBJ"></a>
## @Value是什么?
@Value和@Resource、@Autowired类似也是用来对属性进行依赖注入<br />@Value是用来从Properties文件中获取值的,并且@Value可以解析SpEL(Spring表达式)
- `@Value("zhangsan")`会直接返回字符串赋值给属性,属性不是String会报错
- `@Value("${zhangsan}")`会将可以从Properties对应的value赋值给属性
- 没找到会看做普通字符串注入给属性
- `@Value("#{zhangsan}")`会作为Spring表达式进行解析,
- 会当做beanName在Spring容器中找响应的bean,找到就注入,没有就报错
<a name="eiOUs"></a>
## BeanPostProcessor是什么?
> BeanPostProcesor是Sprig所提供的一种扩展机制,可以利用该机制对Bean进行定制化加工
> 在pring实现中也广泛用到该机制
> BeanPostProcessor通常也叫做Bean后置处理器
> BeanPostProcessor是一种接口
> 自定义一个后置处理器,就是提供类实现该接口
- BeanPostProcessor中的方法
- postProcessBeforeInitialization():初始化前
- 表示可以利用这个方法用来对Bean在初始化前进行自定义加工
- postProcessAfterInitialization():初始化后
- 表示可以利用这个方法用来对Bean在初始化后进行自定义加工
- InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口
- 它还多了一个PostProcessProperties():属性注入后
<a name="GPIxC"></a>
## FactoryBean是什么?
- BeanFactory与FactoryBean是两种不同的接口
- FactoryBeans是Spring提供的一种较灵活的创建Bean的方式,
- 通过FactoryBean接口中的getObject()方法来返回一个对象 ,这个对象是最终Bean对象
- FactoryBean接口中有三个方法:
- Object getObject():返回Bean对象
- boolean isSingleton():返回是否是单例Bean对象
- Class getObjectType():返回Bean对象的类型
- FactoryBean对应者两个Bean对象
- getObject中有一个bean
- FactoryBean本身也是一个bean对象
<a name="Vbxk8"></a>
## @Bean是什么?
- @Bean是用来生成Bean对象,然后将这个Bean对象交给Spring管理,
- @Bean只会调用一次,生成的Bean是单例Bean对象(每次获取(getBean())的Bean都是同一个)
- @Bean默认名为方法名,可以加属性进行指定名
```java
@Service
public class BeanTest{
// @Bean(name="getBean")
@Bean
// @Scope("prototype") // 多例Bean,每次获取的bean都不相同
public BeanTest getBean(){
System.out.println("初始化Bean:")
return new BeanTest();
}
}
public class Main{
public static void main(String[] args){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("xxx.xml");
Object bean1 = context.getBean("getBean");
System.out.println(bean1);
Object bean2 = context.getBean("getBean");
System.out.println(bean2);
}
}
// 自定义Bean注解
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Bean
@Scope("prototype")
public @interface PrototypeBeam {}
@Bean和@Configuration的关系
@Configuration会将当前类注册到Spring中,在调用bean的方法体本身时,不会调用方法体,而是调用方法体注册的Bean对象
在事务调用其他类的方法体时,会产生另一个对象,从而导致事务无法生效
@Component、@ComponentScan
- @Component:是Spring中的一个注解 ,实现Bean的注入
- 在web中提供了三个衍生的@Component注解:
- @Controller、@Service、@Repository
- 在web中提供了三个衍生的@Component注解:
- @ComponentScan:用于扫描过滤排除注解
- 表示扫描指定路径下的带有Component、Controller、Service、Repository
- value属:扫描指定路径
- includeFilters:指定某个包
- excludeFilters:排除某个包
- ComponentScan.Filter:自定排除规则
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照给定的 类型
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则表达式
- FilterType.CUSTOM:使用自定义规则
- classes:指定过滤的类
@Conditional
@Conditional注解是用来判断当前类或当前Bean是否能被注入
如果Conditional中的matches方法返回False,当前类或当前Bean将不被注入public class testCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return false;
}
}
@Service
public class BeanTest {
@Conditional({testCondition.class})
@Bean
public BeanTest getBean02(){
System.out.println("初始化Bean02");
return new BeanTest();
}
}
@Target
Target注解表示这个注解能被使用的范围
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包@Lazy
Spring在程应用程序上下文启动时去创建所有的单例bean,
而@Lazy注解可以延迟加载bean对象,即在使用时才去初始化
@Lazy注解的作用
- 可以减少Spring的IOC容器启动时的加载时间
- 解决bean的循环依赖问题
- ComponentScan.Filter:自定排除规则
@Service
public class BeanTest01 {
public BeanTest02 beanTest02;
// public BeanTest01(@Lazy BeanTest02 beanTest02){
public BeanTest01(BeanTest02 beanTest02){
this.beanTest02 = beanTest02;
}
}
@Service
public class BeanTest02 {
public BeanTest01 beanTest01;
public BeanTest02(BeanTest01 beanTest01) {
this.beanTest01 = beanTest01;
}
}
@Import
@Lookup
@Primary
当在自动注入的过程中,获取到了多个Bean,这时在某个Bean对象中可以给一个@Primary注解
设置为主Bean,在获取多个Bean的时候,不会报错,而是使用主Bean
@Autowired:自动根据类型注入
@Qualifier(“名称”):指定自动注入的id名称
@Async
@Resource(“名称”)
@ PostConstruct 自定义初始化
@ PreDestroy 自定义销毁
@Import
Spring有两种IOC和AOP
IOC是类和类之间进行代理
AOP是方法和方法之间的相互注入
AOP分为两种:静态代理和动态代理,
静态代理:在编译期间,和被代理类实现同样接口,写死类和方法
动态代理是基于jdk的动态代理,proxy在运行时自动根据配置生成被代理类和方法,和被代理类,实现相同的接口