文章目录
Spring注解
@Component, @Controller, @Repository, @Service 有何区别?
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用
@Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
@Import的几种用法
- 直接指定类 (如果配置类会按配置类正常解析、 如果是个普通类就会解析成Bean)
- 通过ImportSelector 可以一次性注册多个,返回一个string[] 每一个值就是类的完整类路径
- 通过DeferredImportSelector可以一次性注册多个,返回一个string[] 每一个值就是类的完整类路径
区别:DeferredImportSelector 顺序靠后 - 通过ImportBeanDefinitionRegistrar 可以一次性注册多个,通过BeanDefinitionRegistry来动态注册BeanDefintion
如何让自动注入没有找到依赖Bean时不报错
这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required
注解的bean属性未被设置,容器将抛出BeanInitializationException。示例:
@Autowired(required = false)
private Role role;
@Autowired 注解
@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。
@Autowired和@Resource之间的区别
@Autowired可用于:构造函数、成员变量、Setter方法
@Autowired和@Resource之间的区别:
- @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为 false)。
- @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
使用@Autowired注解自动装配的过程
@Autowired 通过Bean的后置处理器进行解析的
- 在创建一个Spring上下文的时候再构造函数中进行注册AutowiredAnnotationBeanPostProcessor
- 在Bean的创建过程中进行解析
1.在实例化后预解析(解析@Autowired标注的属性、方法 比如:把属性的类型、名称、属性所在的类… 元数据缓存起)
2.在属性注入真正的解析(拿到上一步缓存的元数据 去ioc容器帮进行查找,并且返回注入)
1)首先根据预解析的元数据拿到 类型去容器中进行查找
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
配置类@Configuration的作用解析原理
- @Configuration用来代替xml配置方式spring.xml配置文件
<bean>
- 没有@Configuration也是可以配置@Bean
- @Configuration加与不加有什么区别?
加了@Configuration会为配置类创建cglib动态代理(保证配置类@Bean方法调用Bean的单例),@Bean方法的调用就会通过容器.getBean进行获取。
原理:
1.创建Spring上下文的时候会注册一个解析配置的处理器ConfigurationClassPostProcessor(实现 BeanFactoryPostProcessor和 BeanDefinitionRegistryPostProcessor)
2.在调用invokeBeanFactoryPostProcessor,就会去调用
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry进行解析配置(解析配置类说白就是去解析各种注解@Bean @Configuration@Import @Component … 就是注册BeanDefinition)
3.ConfigurationClassPostProcessor.postProcessBeanFactory去创建cglib动态代理
Spring AOP
AOP(Aspect-Oriented Programming),一般称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。 而AOP作为面向对象的一种补充,则是针对业务处理过程中的切面进行提取,已达到业务代码和公共行为代码之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
Spring AOP里面的几个名词解释
(1)切面(Aspect): 在Spring Aop指定就是“切面类” ,切面类会管理着切点、通知。
(2)连接点(Join point): 指定就是被增强的业务方法
(3)通知(Advice): 就是需要增加到业务方法中的公共代码, 通知有很多种类型分别可以在需要增加的业务方法,不同位置进行执行(前置通知、后置通知、异常通知、返回通知、环绕通知)
(4)切点(Pointcut): 由他决定哪些方法需要增强、哪些不需要增强,结合切点表达式进行实现
(5)目标对象(Target Object): 指定是增强的对象
(6)织入(Weaving) : spring aop用的织入方式:动态代理,就是为目标对象创建动态代理的过程就叫织入
Spring通知类型
- 前置通知(Before):在目标方法被调用之前调用通知功能;
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
- 返回通知(After-returning ):在目标方法成功执行之后调用通知;
- 异常通知(After-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
执行顺序:
1、正常执行:@Before->方法->@AfterReturning(返回)->@After
2、异常执行:@Before->方法->@AfterThrowing(异常)->@After
AOP的有几种实现方式
- Spring 1.2 基于接口的配置:最早的 Spring AOP 是完全基于几个接口的,想看源码的同学可以从这里起步。
- Spring 2.0 schema-based 配置:Spring 2.0 以后使用 XML 的方式来配置,使用 命名空间
- Spring 2.0 @AspectJ 配置:使用注解的方式来配置,这种方式感觉是最方便的,还有,这里虽然叫做 @AspectJ,但是这个和 AspectJ 其实没啥关系。
- AspectJ 方式,这种方式其实和Spring没有关系,采用AspectJ 进行动态织入的方式实现AOP,需要用AspectJ 单独编译。
什么情况下AOP会失效,怎么解决
失效原因:
- 方法是private 也会失效,解决:改成public
- 目标类没有配置为Bean也会失效, 解决:配置为Bean
- 切点表达式没有配置正确
解决方式:必须走代理, 重新拿到代理对象再次执行方法才能进行增强 - 在本类中自动注入当前的bean
- 设置暴露当前代理对象到本地线程, 可以通过AopContext.currentProxy() 拿到当前正在调用的动态代理对象
@EnableAspectJAutoProxy(exposeProxy = true)
Spring的 Aop的完整实现流程
Aop的实现大致分为三大步:JavaConfig
当@EnableAspectJAutoProxy 会通过@Import注册一个BeanPostProcessor处理AOP
1.解析切面: 在Bean创建之前的第一个Bean后置处理器会去解析切面(解析切面中通知、切点,一个通知就会解析成一个advisor(通知、切点))
2.创建动态代理 正常的Bean初始化后调用BeanPostProcessor 拿到之前缓存的advisor ,再通过advisor中pointcut ,判断当前Bean是否被切点表达式匹配,如果匹配,就会为Bean创建动态代理(创建方式1.jdk动态代理2.cglib)。
3.调用:拿到动态代理对象, 调用方法 就会判断当前方法是否增强的方法,就会通过调用链的方式依次去执行通知.