3.Spring通知(Advice)有哪些类型?
- 前置通知(Before Advice):在连接点(Join point)之前执行的通知。
- 后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
- 环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
- 返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)
- 抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知
注意:定义切点时候,还可以通过自定义注解的方式,此时切点会找到使用自定义注解标注的连接点,然后进行切面的织入。
先自定义一个注解,(不会的小伙伴请补充学习元注解等概念),然后在切面的 PointCut 定义时使用 注解方式,而不是使用表达式方式:
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionAnnotation{
}
// 在需要使用 aop 的地方使用自定义注解标注
@RestController
@RequestMapping(value = "/permission")
public class TestController {
@RequestMapping(value = "/check", method = RequestMethod.POST)
@PermissionsAnnotation()// 添加这个注解
public JSONObject getGroupList(@RequestBody JSONObject request) {
return JSON.parseObject("{\"message\":\"SUCCESS\",\"code\":200}");
}
}
// 表达式定义
@Pointcut("execution(* com.bytebeats.spring4.aop.annotation.service.BankServiceImpl.*(..))")
public void pointcut1() {
}
// 注解定义(定义一个切点,这个切点通过自定义注解作为标识,能够指定连接点)
@Pointcut("@annotation(com.mu.demo.annotation.PermissionAnnotation)")
private void logAdvicePointcut() {
}
4. Spring容器的启动流程:
- 初始化 Spring 容器,注册内置的
BeanPostProcessor
的BeanDefinition
到容器中:- 实例化
BeanFactory
【DefaultListableBeanFactory
】工厂,用于生成Bean对象 - 实例化
BeanDefinitionReader
注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成BeanDefinition
对象,(BeanDefinition
是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName
等) - 实例化
ClassPathBeanDefinitionScanner
路径扫描器,用于对指定的包目录进行扫描查找 bean 对象
- 实例化
- 将配置类的
BeanDefinition
注册到容器中: - 调用refresh()方法刷新容器:
prepareRefresh()
刷新前的预处理:obtainFreshBeanFactory()
:获取在容器初始化时创建的BeanFactory:prepareBeanFactory(beanFactory)
:BeanFactory的预处理工作,向容器中添加一些组件:postProcessBeanFactory(beanFactory)
:子类重写该方法,可以实现在BeanFactory创建并预处理完成以后做进一步的设置invokeBeanFactoryPostProcessors(beanFactory)
:在BeanFactory标准初始化之后执行BeanFactoryPostProcessor的方法,即BeanFactory的后置处理器:registerBeanPostProcessors(beanFactory)
:向容器中注册Bean的后置处理器BeanPostProcessor,它的主要作用是干预Spring初始化bean的流程,从而完成代理、自动注入、循环依赖等功能initMessageSource()
:初始化MessageSource组件,主要用于做国际化功能,消息绑定与消息解析:initApplicationEventMulticaster()
:初始化事件派发器,在注册监听器时会用到:onRefresh()
:留给子容器、子类重写这个方法,在容器刷新的时候可以自定义逻辑registerListeners()
:注册监听器:将容器中所有的ApplicationListener注册到事件派发器中,并派发之前步骤产生的事件:finishBeanFactoryInitialization(beanFactory)
:初始化所有剩下的单实例bean,核心方法是preInstantiateSingletons(),会调用getBean()方法创建对象;finishRefresh()
:发布BeanFactory容器刷新完成事件:
5. BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。
- BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
- 继承MessageSource,因此支持国际化。
- 资源文件访问,如URL和文件(ResourceLoader)。
- 提供在监听器中注册bean的事件。
- BeanFactroy 采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
- ApplicationContext 是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
- ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
- BeanFactory 和 ApplicationContext 都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。