目录

前言:

BeanDefinition的家族系列

1、BeanDefintion的UML类图

2、BeanDefintion家族类详解

2.1、通用接口

2.2、BeanDefintion接口

2.3、AbstractBeanDefintion抽象类

2.4、GenericBeanDefinition类

2.5、 AnnotatedGenericBeanDefinition类

2.6、 ScannedGenericBeanDefinition类

2.7、RootBeanDefinition类

2.8、ChildBeanDefinition类

3、xml配置

         3.1、BeanDefinition的常用属性

3.2、BeanDefinition的继承和注入

3.3、depends-on/init-method/destory-method

3.4、factory-bean/factory-method

3.5、look-up属性

3.6、replace-method属性

  至此BeanDefintion家族相关类以及使用总结完毕。笔者才疏学浅,在本篇博文的分析中如果有理解不到的地方,欢迎大家批评指正。

 

 


前言:

   笔者在一篇关于Spring的BeanFactory的分析的时候数次被BeanDefintion接口弄的云里雾里(有关笔者的Spring源码分析之一BeanFactory相关 感兴趣的可以看看),影响了自己对BeanFactory的阅读。这里趁这次机会好好的捋一捋有关BeanDefinition的家族系列。

一、BeanDefinition的家族系列

   1、BeanDefintion的UML类图

        话不多说直接上图,让我们一睹BeanDefinition的大家族。原谅笔者不才无法用一张UML类图概括完整个BeanDefinition家族

  

                                                                     AnnotatedGenericBeanDefinition UML类图

                                                                        ChildBeanDefinition UML类图

                                                                        RootBeanDefinition UML类图

Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。BeanDefintion是Spring提供的将我们使用xml或者注解修饰的需要spring管理的bean实例统一使用BeanDefintion抽象模式存放,并同时提供有关bean的其他属性信息(spring定义的),注入类型,是否懒加载 ,scope等等,从而便于spring管理和使用。

2、BeanDefintion家族类详解

     2.1、通用接口

 BeanDefintion实现类都会直接或者间接的继承如下接口:    

  1.  AttributeAccessor 接口提供相关属性attribute的设置和读取操作设置属性可以通过xml的<meta key="" value=""/>设置
  2.  BeanMetadataElement接口获取一个包含元数据元素的配置源对象 
  3.  AttributeAccessorSupport抽象类 实现了AttributeAccessor接口  使用Map来提供属性的访问和操作
  4.  BeanMetadataAttributeAccessor类  继承AttributeAccessorSupport 实现BeanMetadataElement  新增的功能是访问BeanMetadataAttribute类型的属性。

    2.2、BeanDefintion接口

            BeanDefintion是Beandefintion系列的顶层接口,继承AttributeAccessor接口和BeanMetadataElement接口 所以具备了访问bean属性 以及获取源对象的功能。  spring将我们需要托管的bean都转换为 BeanDefinition 该接口中包含如下属性setter getter接口方法:

	 parentName: 父beanDefinition 名
	 beanClassName: bean实例对象的class名字
         scope: 单例或者原型
	 lazyInit: 是否懒加载
	 dependsOn: 该bean定义所有依赖的beanName 列表
	 autowireCandidate:是否为注入的候选者    
	    autowire-candidate 属性设置为 false,  这样容器在查找自动装配对象时 将不考虑该 bean,
	    即它不会被考虑作为其他 bean 自动装配的候选者,
	    但是该 bean 本身还是可以使用自动装配来注入其他的 bean
	 primary:是否为唯一的注入候选者
	 factoryBeanName: 创建该bean的工厂BeanName
	 factoryMethodName:创建该bean的工厂MethodName
	 ConstructorArgumentValues:构造参数包装类
	 MutablePropertyValues:可变属性列表
	 scope:是否单例 是否原型
	 role: 用于标识Bean的分类 有三种标识1、用户定义的bean ROLE_APPLICATION 2、某些复杂的配置ROLE_SUPPORT 3、完全内部使用ROLE_INFRASTRUCTURE
	 description 获取描述
         description:返回该bean定义来自的资源的描述(用于在出现错误时显示上下文)
         originatingBeanDefinition:获取原始的bean定义

    2.3、AbstractBeanDefintion抽象类

            AbstractBeanDefintion抽象类完全的实现了BeanDefinition中定义的所有接口(提供了默认的实现方式),同时也提供了一些扩展字段qualifiers属性、MethodOverrides属性等。

// Bean 的Class 对象
private volatile Object beanClass;

// bean 的作用范围, 对应 bean 属性 scope (常见的就是单例/原型)
private String scope = SCOPE_DEFAULT;

// 是否是抽象, 来自 bean 属性的 abstract(抽象的类是不能直接生成对象)
private boolean abstractFlag = false;

// 是否延迟加载, 对应 bean 属性 lazy-init (值是否在使用 Bean的时候才正真的创建 Bean)
private boolean lazyInit = false;

// 自动注入模式, 对应 bean 属性 autowire (这个属性主要指 XML 描述的 beanDefinition, 在生成bean的对吼阶段, 获取容器中的对象, 自动装配在 BeanDefinition 对应的 Field 上)
private int autowireMode = AUTOWIRE_NO;

// 依赖检查, Spring 3.0 后 弃用这个属性
private int dependencyCheck = DEPENDENCY_CHECK_NONE;

// 用来表示一个 bean 的实例化依靠另一个 bean 先实例化(PS: 这个很少使用了)
private String[] dependsOn;

/**
 *  autowire-candidate 属性设置为 false, 
 *  这样容器在查找自动装配对象时
 *  将不考虑该 bean, 即它不会被考虑作为其他 bean 
 *  自动装配的候选者, 但是该 bean 
 *  本身还是可以使用自动装配来注入其他的 bean
 */
private boolean autowireCandidate = true;

// 自动装配时当出现多个 bean 候选者时, 将作为首候选者 (PS: 使用比较少)
private boolean primary = false;

// 用于记录 Qualifier, 对应子元素 qualifier(当使用 @Autowired 时, 有多个候选Bean 时, 就通过这个Qualifier 来进行区分)
private final Map<String, AutowireCandidateQualifier> qualifiers =
        new LinkedHashMap<String, AutowireCandidateQualifier>(0);

// 允许访问非公开的构造器和方法, 程序设置  (PS: 用得比较少)
private boolean nonPublicAccessAllowed = true;

/**
 * 是否以一种宽松的模式解析构造函数, 默认 true
 * 如果是 false, 则在如下情况
 * interface ITest()
 * class ITestImpl implement ITest();
 * class Main {
 *     Main(ITest i) {}
 *     Main(ITestImpl i) {}
 * }
 * 抛出异常, 因为 Spring 无法准确确定哪个构造函数
 * 程序设置
 *
 * lenient 宽大, 仁慈
 */
private boolean lenientConstructorResolution = true;

/**
 * 对应 bean 属性 factory-bean 用法 (PS: 这里涉及 FactoryBean 这个概念, 这个类主要是解决: 创建一个类, 但创建这个类的过程比较长/条件比较多, 这时候就使用同一的抽象工厂模式(FactoryBean对象) 来创建对象)
 * <bean id="instanceFactoryBean" class="example.chapter3.InstanceFactoryBean />
 * <bean id="currentTime" factory-bean="instanceFactoryBean" factory-method="createTime" />
 */
private String factoryBeanName;

// 对应 bean 属性 factory-method
private String factoryMethodName;

// 记录构造函数注入属性, 对应 bean 属性 constructor-arg
private ConstructorArgumentValues constructorArgumentValues;

// 普通属性集合 (在XML 中定义Bean的信息时, 通常propertyValues里面有很多依赖信息)
private MutablePropertyValues propertyValues;

// 方法重写的持有者, 记录 lookup-method, replaced-method 元素(PS: 与此对应有注解Loopup, 但运用的比较少了)
private MethodOverrides methodOverrides = new MethodOverrides();

// 初始化方法, 对应 bean 属性 init-method (PS: 通过 实现InitializingBean 接口, 可以达到同样效果)
private String initMethodName;

// 销毁方法, 对应  bean 属性 destory-method (PS: 与之对应的是 DisposableBean, 一帮都是在这类方法中完成资源释放之类的操作)
private String destroyMethodName;

// 是否执行 init-method, 程序设置  (默认是 true)
private boolean enforceInitMethod = true;

// 是否执行 destory-method, 程序设置 (默认是 true)
private boolean enforceDestroyMethod = true;

// 是否是用户定义的而不是应用程序本身定义的, 创建 AOP 部分组件时为 true(见 ConfigBeanDefinitionbeanParser.parseAdvice 方法)
private boolean synthetic = false;

/**
 * 定义这个 bean 的应用, APPLICATION: 用户, INFRASTRUCTURE(infrastructure 基础设施): 内部使用, 与用户无关, SUPPORT: 某些复杂配置的一部分程序设置, 一般都是 BeanDefinition.ROLE_APPLICATION;
 */
private int role = BeanDefinition.ROLE_APPLICATION;

// bean 的描述信息
private String description;

// 这个 bean 定义的资源 (其实就是 A.class 这个文件)
private Resource resource;

2.4、GenericBeanDefinition类

         该类继承了AbstractBeanDefinition类,提供了一个设置父类BeanDefintion名字的属性,该类可以拥有自己的父类Beandefinition

2.5、 AnnotatedGenericBeanDefinition类

           该类继承了GenericBeanDefinition类,将使用@Configuration 注解修饰的类包装成该类型的BeanDefinition对象。

    //包含@Configuration 注释修改属性信息
	private final AnnotationMetadata metadata;
 
   //存储工厂方法的元数据
	@Nullable
	private MethodMetadata factoryMethodMetadata;

AnnotationGenericBeanDefinition在GenenricBeanDefinition的基础上提供了访问注解、工厂方法的机制

2.6、 ScannedGenericBeanDefinition类

   该类继承了GenericBeanDefinition类,将使用@Component、@Service、@Controller等注解修饰的类包装成该类型的BeanDefinition对象。

   //包含@Component、@Service、@Controller等注释修改属性信息
  private final AnnotationMetadata metadata;

 2.7、RootBeanDefinition类

    RootBeanDefinition可以单独作为一个BeanDefinition,也可以作为其他BeanDefinition的父类。但是他不能作为其他BeanDefinition的子类(可以去看源码,在setParentName的时候,会抛出一个异常) RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善。

2.8、ChildBeanDefinition类

        ChildBeanDefinition相当于一个子类,不可以单独存在,必须要依赖一个父BeanDetintion。(最大的区别他的parentName属性是通过构造方法设置的,而且并没有提供一个无参构造方法给我们。)
 

3、xml配置

     该小结主要使用具体的xml配置的实例,带我们直观的了解BeanDefinition接口中相关属性

  3.1、BeanDefinition的常用属性

  •       spring-beans.xml的配置
<!-- 
       id属性: bean实例的唯一标识
       name属性: name可以存在多个以逗号或者分号分隔 如果存在id和name id为beanName name中会注册为其别名(多个)
                如果没有id 从name中的第一个值逗号或者分号之前的值作为id 其余的作为别名
       class属性:全限定类名
       abstract属性:是否抽象
       scope属性: 单例和原型
       primary属性:声明该bean为自动装配的首选bean
       lazy-init属性:是否懒加载 在使用该实例时候才进行初始化 
      
       bean的子属性
            property 属性使用setter方法去设置bean实例的属性
            name属性:属性名称  基本类型使用value属性赋值  引用类型使用ref属性赋值
            constructor-arg 属性使用构造方法去设置bean实例的属性
            index属性: 指定构造器参数的顺序以0开始
            name属性: 属性名称
            type属性: 指定属性class类型
                    基本类型使用value属性赋值  引用类型使用ref属性赋值
            qualifier属性: 暂时不清楚
            meta属性: BeanDefintion的Attribute属性,当需要里面的属性时,
                      可以通过BeanDefinition的getAttribute(key);方法获取,
            description属性: BeanDefinition的描述信息 要放在开头
-->
<bean id="student" name="student" class="com.xiu.Student" abstract="false" 
        lazy-init="true"   primary="true" scope="singleton" >
        <!--    定义bean实例的描述信息      -->
        <description>这个是一个bean实例的描述</description>
        <!-- 构造器形式的参数赋值 两种形式
             一种使用index索引指定构造器参数的顺序 以0开始同时对应的类也需要有与此构造器参数顺序相关的构造方法 否则会出现提示错误
             另一种 是使用name 显式的指定属性名(这种比较稳妥)
             -->
<!--        <constructor-arg index="1" value="谢"></constructor-arg>-->
<!--        <constructor-arg index="0" value="18"></constructor-arg>-->

        <constructor-arg name="name" value="谢"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>

       <!-- 使用setter getter方法设置实例化的方式 -->
        <property name="name" value="谢"/>
        <property name="age" value="18"/>
        <!-- 设置相关的attributes属性 key属性key值 value属性值-->
        <meta key="key" value="values" />

  
        <!--<qualifier />-->
        <!--<lookup-method/>-->
        <!--<replaced-method/>-->
    </bean>
  •  测试类
  @Test
    public void testBeanDefintion(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        Student student = beanFactory.getBean("student", Student.class);
        System.out.println("姓名:"+student.getName()+", 年龄:"+student.getAge());
        //获取bean定义信息
        BeanDefinition studentBeanDefinition = beanFactory.getBeanDefinition("student");
        //1、获取构造器包装类(前提是使用构造器的形式进行实例化bean)
        ConstructorArgumentValues constructorArgumentValues = studentBeanDefinition.getConstructorArgumentValues();
        List<ConstructorArgumentValues.ValueHolder> genericArgumentValues = constructorArgumentValues.getGenericArgumentValues();
        //获取构造器参数
        System.out.print("获取构造器参数信息");
        genericArgumentValues.stream().forEach(item -> {
            System.out.println("name="+item.getName()+", type="+item.getType()+",value="+item.getValue());
        });
        //2、获取bean定义的属性信息(前提是使用属性property的形式进行实例化bean)
        System.out.print("获取属性信息");
        MutablePropertyValues propertyValues = studentBeanDefinition.getPropertyValues();
        propertyValues.getPropertyValueList().stream().forEach(item->{
            System.out.println("name="+item.getName()+",value="+item.getValue());
        });
        //获取bean实例是否抽象
        System.out.println("是否抽象:"+studentBeanDefinition.isAbstract());
        //是否主要候选者
        System.out.println("是否懒加载:"+studentBeanDefinition.isLazyInit());
        System.out.println("是否为注入的唯一候选bean:"+studentBeanDefinition.isPrimary());

        String scope = studentBeanDefinition.getScope();
        System.out.println("获取scope范围:"+scope);
        //获取xml的meta 属性值
        String value = (String) studentBeanDefinition.getAttribute("key");
        System.out.println("获取attribute属性信息:"+value);
        //获取秒速描述
        String description = studentBeanDefinition.getDescription();
        System.out.println(description);
    }
  • 测试结果              

如上信息都好理解 除了primary属性 我们再下文有关注入功能描述的时候再讲解。

3.2、BeanDefinition的继承和注入

  •   spring bean的xml  parent属性 和autowire属性  autowire-candidate属性
<!--
     parent属性: 设置其父bean实例标识 使用该标识的bean 表明其是一个继承关系
     autowire属性: 如果该bean实例有需要依赖的其他属性bean实例  autowire的意思就是spring帮你匹配容器里的bean,
      而匹配规则有如下几种
          no:不匹配,但是bean必须定义ref元素
          byName:根据名字匹配(如果容器里没有该name的bean,则该属性为null)
          byType:根据类型匹配(如果同时找多个相同类型的bean,则报错)
          constructor:根据构造器匹配
          default:如果在bean上指定了default,则它会去beans标签上去找default-autowire属性
-->  
    <bean id="parent" class="com.xiu.autoeire.Parent">
        <property name="wealth" value="100000000"/>
    </bean>

    <!--autowire-candidate属性:false 设置哪些对象不参与自动注入
   如果有两个类型一样的实例 比如如下的两个bean实例Wife和Daugther 均实现了Woman接口 
    下面的son需要使用Woman引用 默认使用按照类型注入 正常来说 程序会因为不知道如何注入哪一个
    Woman接口实现类出现错误 这时如果在Wife或者Daugther 任何一个实例将其属性设置为false 则该对象
    不会参与自动注入 则程序注入的时候只匹配到一个类型的bean实例 所以会正常使用
    则被注入的时候  会出现无法确定注入哪个对象 如果给其他的类型设置autowire-candidate 为false
    则该实例不会被选择注入-->
    <bean id="wife" class="com.xiu.autoeire.Wife"  autowire-candidate="false">
    </bean>
    <!--注意这里的id lover 和我对应的Son对象中的名字lover保持一致 为了验证ByName -->
    <bean id="lover" class="com.xiu.autoeire.Daughter">
    </bean>
    <!--如果只要spring中一个类型只有一个bean 则可以使用autowire的byType spring会按照类型给
     该bean实例按照class类型注入唯一的WoMan类型  -->
    <bean id="son" class="com.xiu.autoeire.Son" parent="parent" >
        <property name="life" value="泡妞"/>
    </bean>
  •  测试类
//父类
public class Parent {
    //财富
    private Double  wealth;
    //省略构造器和setter getter方法
}
public class Son extends Parent {
    private String life;
    //该属性用来验证autowire模式
    private Woman lover;
   //省略构造器和setter getter方法
}
//接口类
public interface Woman {
    public void love();
}
public class Wife implements Woman {
    @Override
    public void love() {
        System.out.println("我是妻子");
    }
}
public class Daughter implements Woman {
    @Override
    public void love() {
        System.out.println("我是我爸的上辈子的情人");
    }
}
    @Test
    public void testAutoWire(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        Son son = beanFactory.getBean("son", Son.class);

        //Son继承了Parent的 该实例通过在son的实例配置xml 中使用parent属性 则son自动继承了父类的Wealth
        System.out.println("我是富二代,我有"+son.getWealth()+"钱,我要去"+son.getLife());
        //自动注入 通过类型 通过名字 等
        son.action();
    }
  •    测试结果

3.3、depends-on/init-method/destory-method

     spring bean的xml配置

    <!--
      depends-on属性:depends-on是指相对于ref强关联关系  关联关系不强的两者属性依赖使用的depends-on
      比如系统需要启动多个服务 用户服务,订单服务等 只有多个服务启动成功后,才启动系统 这个产品可以使用该属性.
      同时指定Bean初始化及销毁时的顺序,使用depends-on属性指定的Bean要先初始化完毕后才初始化当前Bean,
      由于只有"singleton"Bean才能被Spring管理销毁,所以当指定的Bean都是"singleton"时,
      使用depends-on属性指定的Bean要在指定的Bean之后销毁。衍生出如下的实例初始化init-method属性 和销毁调用 destroy-method属性
      init-method属性: 初始化之前调用该init-method方法
      destroy-method属性: bean实例被销毁后调用该destroy-method方法
    -->
    <!-- 用户服务 -->
    <bean id="userService" class="com.xiu.service.dependson.UserService" 
         init-method="initMethod" destroy-method="destoryMethod"/>
    <!-- 订单服务 -->
    <bean id="orderService" class="com.xiu.service.dependson.OrderService" 
            init-method="initMethod" destroy-method="destoryMethod" />
   <!-- 系统服务 -->
    <bean id="system" class="com.xiu.service.dependson.MySystem"
            depends-on="orderService,userService"  init-method="initMethod" 
          destroy-method="destoryMethod"/>

  •   bean实例配置

  用户服务类

//用户服务
public class UserService {
    public void initMethod(){
        System.out.println("用户服务实例化的初始化方法调用");
    }
    public void destoryMethod(){
        System.out.println("用户服务实例化的销毁方法调用");
    }
    public UserService(){
        System.out.println("用户服务启动完成");
    }
}

  订单服务类

//订单服务
public class OrderService  {
    public void initMethod(){
        System.out.println("订单服务实例化的初始化方法调用");
    }
    public void destoryMethod(){
        System.out.println("订单服务实例化的销毁方法调用");
    }
    public OrderService(){
        System.out.println("订单服务启动完成");
    }
}

  系统类

//系统类
public class MySystem {
    public void initMethod(){
        System.out.println("系统实例化的初始化方法调用");
    }
    public void destoryMethod(){
        System.out.println("系统实例化的销毁方法调用");
    }
    public MySystem(){
        System.out.println("系统启动完成");
    }
}

测试类

  @Test
    public void testDependOnAndInitDestory(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        //获取系统
        MySystem system = beanFactory.getBean("system", MySystem.class);
        //销毁某个服务 则对应依赖该服务的系统也会被销毁
        beanFactory.destroySingleton("userService");
    }
  • 输出结果:

      总结:在三个服务类中都设置了init-method 和destory-method 两个方式 实例创建的时候会调用对应的init-method对应的方法,同时代码中销毁用户服务 其destory-method对应的方法会被调用。

          再来说一下 depends-on属性,除了上面的场景下(依赖关系上面的xml配置已经讲述清除)之外。这里说一下depends-on依赖关系下 依赖方与被依赖方初始化和销毁顺序,从打印的日志可以清楚的知道MySystem 依赖UserService和OrderService,则获取MySystem时候先回初始化其depends-on依赖的UserService和OrderService(先执行两者的init-method对应的方法)

销毁的时候 如果销毁MySystem depends-on依赖的UserService和OrderService任何一个则需要先销毁MySystem实例。

3.4、factory-bean/factory-method

  •  spring 的bean xml配置
  <!--
     factory-bean/factory-method属性: 使用工厂方法注入bean 创建实例的bean 如果方法是静态方法 只需要使用factory-method属性
               如果创建bean实例的的方法是工厂对象的非静态方法 则需要使用factory-bean 指明工厂bean实例 同时使用factory-method指明创建bean实例的方法名
   -->
    <!--实例化工厂对象-->
    <!-- 使用非静态工厂方法获取对象 需要先实例化工厂对象 -->
    <bean id="productFactory" class="com.xiu.service.factory.ProductFactory"  />
    <bean id="product"
          factory-bean="productFactory"  factory-method="createProduct"/>
    <!-- 使用静态工厂方法获取对象 -->
        <bean id="productStatic" class="com.xiu.service.factory.ProductFactory"
              factory-method="createProductStatic"/>
  • java类
public class Product {
    public Product(){
        System.out.println("创建产品成功");
    }
}

//工厂类
public class ProductFactory {
    //静态方法创建产品
    public static Product createProductStatic(){
        final Product product = new Product();
        return product;
    }
    //非静态方法创建产品
    public Product createProduct(){
        final Product product = new Product();
        return product;
    }
}

测试类

  @Test
    public void testProductByFactory(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        //通过静态工厂方法获取产品
        Product productStatic = beanFactory.getBean("productStatic", Product.class);
        //通过非静态工厂方法获取产品
        Product product = beanFactory.getBean("product", Product.class);
    }
  • 输出结果

3.5、look-up属性

  • spring bean xml配置
 <!--
        lookup-method属性: 假设一个单例模式的bean A需要引用另外一个非单例模式的bean B,为了在我们每次引用的时候都能拿到最新的bean B
                           所以Spring为我们提供了方法注入的方式来实现以上的场景。方法注入方式主要是通过<lookup-method/>标签
     -->
        <!-- 原型香蕉实例 -->
        <bean id="banner" class="com.xiu.service.lookup.BannerFruit" scope="prototype" />
        <!-- 原型苹果实例 -->
        <bean id="apple" class="com.xiu.service.lookup.AppleFruit" scope="prototype" />

       <!--getFreshFruit是一个抽象方法 具体的实现通过CGLIB 动态代理自动生成代理方法 同时将最新的水果实例返回
           这样才能获取到“新鲜”水果-->
        <bean id="fruitTray" class="com.xiu.service.lookup.FruitTray">
            <lookup-method name="getFreshFruit" bean="banner"/>
        </bean>
  • java类配置
//水果接口
public interface Fruit {
    public void getFruit();
}

//苹果水果类
public class AppleFruit implements Fruit {
    @Override
    public void getFruit() {
        System.out.println("获取到新鲜的苹果");
    }
}

//香蕉水果
public class BannerFruit implements Fruit {
    @Override
    public void getFruit() {
        System.out.println("获取到新鲜的香蕉");
    }
}

//果盘
public abstract class FruitTray {
    //获取新鲜的水果 抽象方法 
    public abstract Fruit  getFreshFruit();
}

测试类

   @Test
    public void testLookUp(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        FruitTray fruitTray = beanFactory.getBean("fruitTray", FruitTray.class);

        Fruit freshFruit = fruitTray.getFreshFruit();

        freshFruit.getFruit();
    }
  • 输出结果

3.6、replace-method属性

  •  spring bean xml配置
    <!-- replaced-method属性: 使用场景:动态替换原有的业务逻辑  -->
        <bean id="gangster" class="com.xiu.service.replace.Gangster" >
            <replaced-method name="action"  replacer="undercover" />
        </bean>
        <bean id="undercover" class="com.xiu.service.replace.Undercover" >
        </bean>
  •  java类
//原始类
public class Gangster {
    public void action() { System.out.println("原始方法!");
    }
}

//动态改变功能的类  需要实现MethodReplacer 接口中的reimplement方法
public class Undercover implements MethodReplacer {
    public void action(){
        System.out.println("方法已经被替换");
    }
    //该方法类似于动态代理
    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        action();
        return null;
    }
}

测试类

   @Test
    public void testReplaced(){
        XmlBeanFactory  beanFactory = new XmlBeanFactory(new ClassPathResource("spring-beans.xml"));
        Gangster gangster = beanFactory.getBean("gangster", Gangster.class);
        gangster.action();
    }
  •   输出结果

 

  至此BeanDefintion家族相关类以及使用总结完毕。笔者才疏学浅,在本篇博文的分析中如果有理解不到的地方,欢迎大家批评指正。

 

 

更多推荐

spring源码分析之BeanDefinition相关