[SpringBoot ]:IoC,DI, AOP,自动配置与起步依赖

摘要

摘要:IoC;AOP;自动配置;起步依赖;Spring Bean循环依赖

说明:IoC、DI均为软件工程中思想,致力提高“高内聚,低耦合”的软件设计思路。

1 IoC(Inverse Of Controller)

什么是IOC?(Inverse Of Controller)控制反转,把对象的创建权(new对象), 反转为 Spring容器管理,IOC创建的对象称之为Bean对象

1.1 声明bean的注解?(即把对象放入容器中的注解)

注解说明
@Component不属于以上三类时,用此注解
@Controller标注在控制层类上
@Service标注在业务类上
@Repository标注在数据访问层类上

2 DI(Dependency Injection)

什么是DI?(Dependency Injection)依赖注入,给容器中bean的属性赋值,常用使用方式,使用@Autowired注解声明在需要注入的类上,此时就会去spring容器中寻找Bean对象

2.1 DI注解类型

注解说明指定属性值
@Autowired按照类型注入① @Autowired(required=true):注入时,该bean必须存在,否则就注入失败,默认就是; ② @Autowired(required=false):注入bean时,若有直接注入,没有则跳过,不会报错。
@Qualifier按照名称注入 要和@Autowired搭配使用
@Resource按照名称注入 = @Autowired + @Qualifier

2.2 DI注解类型方法示例

2.2.1 @Autowired

@Autowired
private Date date ;

2.2.2 @Qualifier

@Autowired
@Qualifier("birth")
private Date birthday ;

2.2.3 @Resource

@Resource(name = “apple”)

3 AOP(面向切面编程)

3.1 什么是AOP?

面向切面编程

3.2 AOP的作用?

在不改变原始代码的基础上进行功能增强

3.3 AOP的核心概念

名词解释
连接点所有可以进行功能增强的方法都是连接点
切入点进行了功能增强的方法就是切入点
通知共性功能
切面切入点 + 通知
目标对象通知所应用的对象就是目标对
切入点表达式指定哪些方法是切入点

3.4 AOP常见通知类型

通知类型解释注意事项
@Before前置通知
@After后置通知
@Around环绕通知① @Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 让原始方法执行,其他通知不需要考虑; ② @Around环绕通知方法返回值必须指定为Object,来接收原始方法的返回值否则原始方法执行完毕,获取不到返回值
@AfterReturning返回后通知
@AfterThrowing异常后通知

3.5 切入点表达式

写法一:@PointCut("execution(访问修饰符 返回值 包名.类名.方法名(参数))")

  • 通配符:
    * 单个独立的任意符号,通配任意返回值、包名、类名、方法名、任意类型的参数,也通配包、类、方法名的一部分
    .. 多个连续任意符号,用于参数省略包名省略

写法二:@PointCut("@annotation(注解的全路径类名)")

  • 通过连接点对象获取目标方法的信息
    获取类名:joinPoint.getTarget().getClass().getName()
  • 获取方法名:joinPoint.getSignature().getName()
  • 获取参数:joinPoint.getArgs()
  • 执行目标方法:joinPoint.proceed()
  • 获取返回值:Object result = joinPoint.proceed()

切入点表达式的语法规则:

  • 方法的访问修饰符可以省略
  • 返回值*号代替(任意返回值类型
  • 包名使用*号代替,代表任意包(一层包使用一个*
  • 使用..配置包名,标识此包及此包下所有子包
  • 类名使用*号代替,标识任意类
  • 方法名使用*号代替,表示任意方法
  • 使用 * 配置参数,一个任意类型的参数
  • 使用.. 配置参数,任意个任意类型的参数

3.5.1 切入点表达式练习一

注意事项:

  • 根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式
execution(* com.sesameseed.service.DeptService.list(..)) || execution(* com.sesameseed.service.DeptService.delete(..))

解释切入点为DeptService接口(全路径)下,参数为任意类型和个数,且返回值为任意的list方法,或DeptService接口下,参数为任意类型和个数,且返回值为任意的delete方法。

*com*任意返回值.
(. .)表示任意类型和个数的参数
.DeptService.list(. .)DeptService接口下,参数为任意类型和个数的list方法表示

3.5.2 切入点表达式练习二

@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")

解释切入点为mapper包下,任意包名,任意方法,且被@AutoFill注解声明。

3.5.3 抽取冗余切入点表达式

引入,对于下方代码来说,每一个注解里面都用到相同切入点表达式,所以我们可以把它抽取出来。

//前置通知
@Before("execution(* com.itheima.service.*.*(..))")

//环绕通知
@Around("execution(* com.itheima.service.*.*(..))")
  
//后置通知
@After("execution(* com.itheima.service.*.*(..))")

//返回后通知(程序在正常执行的情况下,会执行的后置通知)
@AfterReturning("execution(* com.itheima.service.*.*(..))")

//异常通知(程序在出现异常的情况下,执行的后置通知)
@AfterThrowing("execution(* com.itheima.service.*.*(..))")

3.5.4 抽取冗余切入点表达式示例

注解说明
@PointCut将公共的切入点表达式抽取出来
@Slf4j
@Component
@Aspect
public class MyAspect1 {

    //切入点方法(公共的切入点表达式)
    @Pointcut("execution(* com.itheima.service.*.*(..))")
    private void pt(){

    }

    //前置通知(引用切入点)
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info("before ...");

    }

    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info("around before ...");

        //调用目标对象的原始方法执行
        Object result = proceedingJoinPoint.proceed();
        //原始方法在执行时:发生异常
        //后续代码不在执行

        log.info("around after ...");
        return result;
    }

注意:在当前类外部引切入点表达式,需要把private改为public,语法为全类名.方法名(),示例如下:

public class MyAspect2 {
   //引用MyAspect1切面类中的切入点表达式
@Before("com.itheima.aspect.MyAspect1.pt()")
   public void before(){
       log.info("MyAspect2 -> before ...");
   }
}

3.6 连接点

连接点:可以被AOP控制的方法

在Spring中JoinPoint抽象连接点,可以获得方法执行时相关信息,如目标类名方法名方法参数等。

通知类型获取连接点信息方法
@AroundProceedingJoinPoint类型
其他四种通知JoinPoint类型

3.6.1 代码示例

    @Pointcut("@annotation(com.itheima.anno.MyLog)")
    private void pt(){}
   
    //前置通知
    @Before("pt()")
    public void before(JoinPoint joinPoint){
        log.info(joinPoint.getSignature().getName() + " MyAspect7 -> before ...");
    }
    
    //后置通知
    @Before("pt()")
    public void after(JoinPoint joinPoint){
        log.info(joinPoint.getSignature().getName() + " MyAspect7 -> after ...");
    }

    //环绕通知
    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取目标类名
        String name = pjp.getTarget().getClass().getName();
        log.info("目标类名:{}",name);

        //目标方法名
        String methodName = pjp.getSignature().getName();
        log.info("目标方法名:{}",methodName);

        //获取方法执行时需要的参数
        Object[] args = pjp.getArgs();
        log.info("目标方法参数:{}", Arrays.toString(args));

        //执行原始方法
        Object returnValue = pjp.proceed();

        return returnValue;
    }

4 自动配置

4.1 简述:SpringBoot自动配置的原理

  • ① 在Springboot启动的时候,会用到核心注解@SpringBootApplication
  • ② 这个注解中有一个自动配置注解@EnableAutoConfiguration@SpringBootConfiguration,其中@SpringBootConfiguration可以让我们在启动类上跟@Bean完成第三方jar包的自动装配。
  • ③ 其次,自动配置注解会通过@Import注解导入AutoConfigurationImportSelector,这个类实现了一个导入器接口ImportSelector,自动寻找META-INF/spring.factories 和 AutoConfiguration.imports 文件中的xxxAutoConfiguration自动配置类,在自动配置中使用@Bean会根据条件注解所指定的条件,把一些配置类和bean对象放到了Spring容器中,就完成了自动配置
  • 自动配置注解:@EnableAutoConfiguration
  • 自动配置文件:spring.factories 和 AutoConfiguration.imports 文件
  • 自动配置类:xxxAutoConfiguration(@Bean).
注解说明
@Bean告诉方法,产生一个Bean对象并交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后被放在Spring容器中。

4.2 源码跟踪

spring.factories
Spring Boot 中的SPI 机制(Java SPI 机制):为某个接口寻找服务的实现的机制,类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制很重要。

  • 当需要实现SDK 或Sring boot starter 给别人调用,使用Factories机制(Spring Boot 中的SPI 机制)可以让SDK或Stater的使用只需很少或不需要进行配置,只需在服务中引入我们的Jar包就即可。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 起步依赖

springboot的起步依赖主要依靠maven的继承版本控制,从而完成起步依赖。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 Spring Bean循环依赖

6.1 什么是Spring Bean循环依赖

Spring Bean循环依赖:值在Bean间存在相互依赖的情况,互相依赖的Bean无法实例化。

  • 举例:在A类中声明了成员变量B,B中也声明的成员变量A,即双方相互依赖,若在初始化Bean时不加限制的注入会导致循环依赖问题。

6.2 如何解决Spring Bean循环依赖

6.2.1 三级缓存

三级缓存:即提前暴露出来的单例对象缓存,实现Bean的提前曝光,Spring会首先实例化Bean。但是Bean中的依赖项只能通过代理方式设置,这样Spring可以在对象创建前就处理好依赖关系,若Bean中属性正在被注入,Spring容器会提供一个**代理对象**,以处理互相依赖的管理,即若存在Bean的依赖关系,spring会在添加代理之后,提前将一个缓存对象返回并注册,这样Bean间就可以保持互相依赖关系

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值