springboot 中 bean 的管理/代理

Felix 2022年05月29日 26次浏览

Why

springMVC 通过 IOC 提供了对 bean 的管理机制,让开发人员更专注于业务逻辑,节省开发成本。
又通过 三级缓存 的方式来解决 bean 在初始化时的 循环依赖问题。
那么本来通过二级缓存就可以解决的问题,为什么需要使用三级缓存呢?
就是为了更好的一次性解决通过 AOP 实现的某些特定功能增强,所以多加了一层代理factorybean来处理需要代理的 bean。

What

springMVC 管理的 bean 通常分为两种, 原始实例对象 和 代理对象。

When

原始对象

当需要实例化的类中没有实现接口或者进行 AOP 功能增强,那么springMVC 会直接初始化这个对象,最后将该原始对象添加到 bean list里面。

代理对象

当需要实例化的类中有接口的实现 / 继承/ AOP 增强, 那么 SpringMVC 会对该对象生成代理对象,方便后期注入 / 增强, 最后将代理对象添加到 bean list里面。

Select

Spring5.x - 版本默认使用 jdk 代理模式,但是由于 jdk 代理模式只能注入到接口声明的属性变量中,所以springboot2.x 将动态代理改为 cglib 代理模式, cglib 代理模式生成的代理对象是继承于原始对象实现的,所以可以实现各种变量代理注入。

Test

env: SpringBoot2.7.0
dependencies: web / aop

// Component 声明 bean
@Component
public class IndexService {
    public String index() {
        return "index";
    }
}
// Service 声明bean, 无接口实现
@Service
public class ProxyService {
    public String index() {
        return "proxy service";
    }
}

// Service 声明bean, 实现接口
public interface IIndexService {
    public String index();
}
@Service
public class IndexServiceImp implements IIndexService{
    @Override
    public String index() {
        return "interface index";
    }
}

// AOP 切入serviec,模拟功能增强
@Aspect
@Component
public class ServiceLogAop {
    @Pointcut("@within(org.springframework.stereotype.Service)")
    public void service() {}

    @Around("service()")
    public Object service(ProceedingJoinPoint joinPoint) throws Throwable {
        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        final Object obj = joinPoint.proceed();
        System.out.println("================>" + className + "/" + methodName);
        return obj;
    }
}
// 运行
@SpringBootApplication
@RestController
@RequestMapping("/")
public class DemoBeanApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoBeanApplication.class, args);
    }
    private IndexService indexService;
    private ProxyService proxyService;
    private IIndexService iIndexService;
    @Autowired
    public DemoBeanApplication(IndexService indexService, ProxyService proxyService, IIndexService iIndexService) {
        this.indexService = indexService;
        this.proxyService = proxyService;
        this.iIndexService = iIndexService;
    }

    @GetMapping("/")
    public String index() {
        System.out.println("indexService=============" + indexService.getClass().getName());
        System.out.println("proxyService=============" + proxyService.getClass().getName());
        System.out.println("iIndexService=============" + iIndexService.getClass().getName());
        return proxyService.index();
    }
}
// 打印log 
indexService=============com.example.demo_bean.IndexService
proxyService=============com.example.demo_bean.ProxyService$$EnhancerBySpringCGLIB$$69c7f339
iIndexService=============com.example.demo_bean.IndexServiceImp$$EnhancerBySpringCGLIB$$26d546cd
================>com.example.demo_bean.ProxyService/index