谈谈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和ApplicationContextBeanFactory和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. 实例化Bean1. 对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个未初始化的依赖时,容器就会调用createBean进行实例化1. 对于ApplicationContxt容器,当容器已启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean2. 设置对象属性(注入依赖)1. 实例化后的对象封装到BeanWrapper对象中,Spring工具BeanDefinition中的信息,以及通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入3. 处理Aware接口1. Spring会检测该对象是否实现`xxxAware`接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源1. Bean实现BeanNameAware接口会调用它实现`setBeanName(String beanId)`方法,传入bean的名字1. Bean实现BeanClassLoaderAware接口,调用setBeanClassLoader()方法,转入ClassLoader1. Bean实现BeanFactoryAware接口,调用setBeanFactory()方,传传递Spring工厂自身1. Bean实现了ApplicationContextAware接口,会调用serApplicationContext(ApplicationContext)方法,传入Spring上下文4. BeanPostProcessor前置处理1. 对bean进行一些自定义的前置处理,可以让bean实现BeanPostProcessor接口,调用1. `POSTProcessBeforeInitialization(Object obj, String str)`方法5. InitializingBean1. 如果bean实现了InitializationBean方法,执行`afeterPropertiesSet()`方法6. init-method1. 如果bean在spring配置文件中配置了init-method属性,则会自动调用其配置的初始化方法7. BeanPostProcessor后置处理1. 如果bean实现BeanPostProcessor接口,将会调用1. `postProcessAfterInitialization(Object obj, String str)`1. 由于这个方法是在bean初始化结束时调用的,所以可以被应用于内存或缓存技术8. DisposableBean1. 当bean不再需要时,会经过处理阶段,如果bean实现了DisposableBean这个接口,会被调用destroy()方法9. destroy-method1. 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)有实例变量的对象,可以保存数据,非安全bean1. 无状态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属性来进行装配bean1. 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>## BeanFactoryBeanFactory(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. @Component1. @Bean1. @Import1. BeanDefinitionRegistryPostProcessor1. FactoryBean1. 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@Servicepublic 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 {@Overridepublic boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {return false;}}@Servicepublic class BeanTest {@Conditional({testCondition.class})@Beanpublic 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:自定排除规则
@Servicepublic class BeanTest01 {public BeanTest02 beanTest02;// public BeanTest01(@Lazy BeanTest02 beanTest02){public BeanTest01(BeanTest02 beanTest02){this.beanTest02 = beanTest02;}}@Servicepublic 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在运行时自动根据配置生成被代理类和方法,和被代理类,实现相同的接口
