Spring之@Lookup

1.现象说明

当一个单例bean注入一个原型bean,原型bean的特性会消失

写一个例子演示现象

创建实体类Car Person

package com.test.bd.component;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope(scopeName = "prototype")
public class Car {
}
package com.test.bd.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Person {

    @Autowired
    private Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

创建配置类

package com.test.bd.config;


import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.test.bd")
public class AppConfig {

}

创建启动类

package com.test.bd;

import com.test.bd.component.Car;
import com.test.bd.component.Person;
import com.test.bd.config.AppConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        Person p1 = context.getBean(Person.class);
        Car car1 = p1.getCar();

        Person p2 = context.getBean(Person.class);
        Car car2 = p2.getCar();

        boolean equation = (car1 == car2);

        System.out.println(equation);

    }
}

运行main方法,查看运行结果

两个car是同一个对象,没有体现原型的特性

2.使用@Lookup注解解决上述问题

 修改实体类Person

package com.test.bd.component;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

@Component
public class Person {

    //@Autowired
    private Car car;

    @Lookup
    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }
}

再次运行main方法,查看运行结果

两个car不是同一个对象,体现了原型的特性

3.源码分析

第一阶段 BeanDefinition对象相关属性赋值

当我们实例化Person对象的时候,会执行一个推断构造方法的方法(determineConstructorsFromBeanPostProcessors),这个方法会循环执行bpp的determineCandidateConstructors方法,其中一个子类实现AutowiredAnnotationBeanPostProcessor会处理@Lookup注解(给BeanDefinition的methodOverrides属性设置值)

相关方法

  1. AbstractAutowireCapableBeanFactory#createBeanInstance
  2. AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors
  3. AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors 
第二阶段 动态代理

在后面的某个阶段会判断BeanDefinition的methodOverrides属性是否为空,当methodOverrides属性不为空则进行cglib动态代理,动态代理的时候会注册LookupOverrideMethodInterceptor拦截器

相关方法

  1. AbstractAutowireCapableBeanFactory#instantiateBean
  2. SimpleInstantiationStrategy#instantiate
  3. CglibSubclassingInstantiationStrategy#instantiateWithMethodInjection
第三阶段 分析LookupOverrideMethodInterceptor执行流程

当我们执行getCar方法的时候,拦截器不会返回bean注入的car,而是去beanFactory中重新获取,因为Car是一个原型bean,所以两次取出来的值不一样

 相关方法

  1. LookupOverrideMethodInterceptor#intercept
  2. DefaultListableBeanFactory#getBeanProvider
  3. DefaultListableBeanFactory#resolveBean
  4. DefaultListableBeanFactory#resolveNamedBean

总结

如果类中存在@Lookup标注的方法,Spring在实例化bean的时候会进行动态代理,注册一个LookupOverrideMethodInterceptor拦截器。后期如果我们调用@Lookup标注的方法,就会进入拦截器的intercept方法,该ntercept方法通过beanFactory.getBean重新获取bean

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值