ソース春シリーズ - (ソースコード解析で)アプリケーションを展開するFactoryBeanの

序文

春のコアIOCコンテナに学習するとき、あなたは確かに、最も基本的なたBeanFactoryこのSpringのIoCコンテナと接触することになります。これは、クラスにさらされたときに、私たちが学ぶ最初のソース春でなければなりません。スプリングFactoryBeanのもこのクラスに存在する、綴り及び周波数の両方に非常に類似して非常に高いです。いくつかの春の顔の質問では、私は違いは、両方の何を聞いてきます。

私はここで結論をお話しましょう:

  • たBeanFactory:すべての春の豆工場でのIoCコンテナの春
  • FactoryBeanの:変更されたオブジェクトまたはオブジェクト発電プラント豆、その実装および工場モードのモデル及び変形モードと同様の設計を生成するための簡単な豆豆、

ソース春のソースコードやその他のオープンソースプロジェクトを学習するプロセスでは、多くの場合、春のカテゴリに統合するために使用されるいくつかのFactoryBeanのフレームワークを見つけ、この記事では、特定のFactoryBeanのは、シンプルで実用的な、特定のアプリケーション開発で説明します。

FactoryBeanのは何ですか

春豆の2種類があり、一つは共通豆、別の工場豆すなわちFactoryBeanのです。

一般的に、春の反射は、Beanをインスタンス化するBeanクラスを使用してクラスを指定します。いくつかのケースでは、豆のプロセスの例は、従来の方法に必要である場合など、複雑で<bean>構成大量の情報を提供するために、符号化方法が簡単に得るために使用することができる場合の構成の自由度が制限されプログラム。バネが提供することを目的とするorg.Springframework.bean.factory.FactoryBean植物ベースのインターフェースを、ユーザが豆のこのインターフェースカスタマイズロジックのインスタンスを実装することができます(後者のいくつかの例をより深く理解するを参照してください)

設定の際に、<bean>プロセスは非常に複雑であり、作成プロセスは、他の多くの豆や複雑なロジックを伴う使用のXML設定が困難であり、あなたはFactoryBeanのの使用を検討することができます

インタフェース定義

package org.springframework.beans.factory;

public interface FactoryBean<T> {
	T getObject() throws Exception;
	
	Class<?> getObjectType();
	
	boolean isSingleton();
}
复制代码

いくつかのオープンソースフレームワークで使用されます

MyBatisのスプリング#SqlSessionFactoryBean

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="***" />
        <property name="configLocation" value="***"/>
        <property name="mapperLocations" value="***"/>
    </bean>
复制代码
public class SqlSessionFactoryBean
    implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
	...
}
复制代码

アリオープンソースの分散サービスフレームワークダボ#ReferenceBean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
 
    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="consumer-of-helloworld-app"  />
 
    <!-- 使用multicast广播注册中心暴露发现服务地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234" />
 
    <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
    <dubbo:reference id="demoService" interface="org.apache.dubbo.demo.DemoService" />
</beans>
复制代码

<dubbo:referenceビーンは対応しているcom.alibaba.dubbo.config.spring.ReferenceBeanクラス

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
	...
}
复制代码

実践を展開

巻き込みます

  • ProduceLocation産地
  • 素材・材質
  • ProductFactoryBean豆製品工場
  • 製品製品
  • ブートストラップ・スタートアップ・クラス
  • テストテスト-config.xml構成ファイル

ProduceLocation

@Data
public class ProduceLocation {

    private String locationName;

    private double distanceKm;

    private double pricePerPerKm;
}
复制代码

材料

@Data
public class Material {

    private String name;

    private double pricePerGram;

    private double weight;
}
复制代码

製品

@Data
@Builder
public class Product {

    private Material material;

    private ProduceLocation location;

    private double price;
}
复制代码

ProductFactoryBean

@Setter
@Getter
public class ProductFactoryBean implements FactoryBean<Product> {

    private Material material;

    private ProduceLocation produceLocation;

    @Override
    public Product getObject() throws Exception {
        return Product.builder()
                .location(produceLocation)
                .material(material)
                .price(cal(material, produceLocation))
                .build();
    }

    private double cal(Material material, ProduceLocation produceLocation) {
        return material.getPricePerGram() * material.getWeight()
                + produceLocation.getDistanceKm() * produceLocation.getPricePerPerKm();
    }

    @Override
    public Class<?> getObjectType() {
        return Product.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
复制代码

テスト-config.xmlの

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

    <bean id="produceLocation" class="base.ioc.FactoryBeanDemoSet.ProduceLocation">
        <property name="locationName" value="杭州"/>
        <property name="pricePerPerKm" value="151.01"/>
        <property name="distanceKm" value="3.1"/>
    </bean>
    <bean id="material" class="base.ioc.FactoryBeanDemoSet.Material">
        <property name="name" value="巧克力豆"/>
        <property name="pricePerGram" value="100"/>
        <property name="weight" value="50"/>
    </bean>
    <bean id="product" class="base.ioc.FactoryBeanDemoSet.ProductFactoryBean">
        <property name="material" ref="material"/>
        <property name="produceLocation" ref="produceLocation"/>
    </bean>
</beans>

复制代码

ブートストラップ

/**
 * @author Richard_yyf
 * @version 1.0 2019/9/21
 */
public class Bootstrap {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test-config.xml");
        Product product = (Product) context.getBean("product");
        System.out.println(product.toString());
    }
}
复制代码

輸出

Product(material=Material(name=巧克力豆, pricePerGram=100.0, weight=50.0), location=ProduceLocation(locationName=杭州, distanceKm=3.1, pricePerPerKm=151.01), price=5468.131)
复制代码

もちろん、缶、上記の構成であっても実行するJavaの設定方法を使用します。

上記の単純なビジネスの一例である、あなたはまた、いくつかのオープンソースツールのAPIを使用することができ、このようなHttpClientをの作成などFactoryBeanのことでいくつかのパッケージは、タイムアウトなど、いくつかのパッケージ、接続プールのサイズは、httpや他のエージェントをしました。

プロパティ

与えられたid=mybeanFactoryBeanののを、getBean("mybean")このオブジェクトのインスタンスが作成されるFactoryBeanの取得、そしてgetBean("&mybean")本当にFactoryBeanの独自のオブジェクトを取得します。

デモによると、次のコードを実行します。

/**
 * @author Richard_yyf
 * @version 1.0 2019/9/21
 */
public class Bootstrap {

    public static void main(String[] args) throws Exception {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test-config.xml");
        // Product product = (Product) context.getBean("product");
        // System.out.println(product.toString());
        
        FactoryBean<Product> factoryBean = (ProductFactoryBean) context.getBean("&product");
        System.out.println(factoryBean.getObject().toString());
    }
}
复制代码

出力

Product(material=Material(name=巧克力豆, pricePerGram=100.0, weight=50.0), location=ProduceLocation(locationName=杭州, distanceKm=3.1, pricePerPerKm=151.01), price=5468.131)
复制代码

対応するソースコード

直接論理ソースの対応するロックされ、

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
        // BeanFactoryUtils.isFactoryDereference(name)方法判断name是否以&前缀
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}
        
       // Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			if (mbd == null && containsBeanDefinition(beanName)) {
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
    }
复制代码
  1. BeanFactoryUtils.isFactoryDereference(name)取得するかどうかを決定するためにFactoryBean参照の

    	// 不为空且以”&“开头
    	public static boolean isFactoryDereference(String name) {
    		return (name != null && name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
    	}
    	String FACTORY_BEAN_PREFIX = "&";
    复制代码
  2. 着信があればbeanInstanceないFactoryBeanが、呼び出し側が取得するために使用されるFactoryBean基準時間を、スローBeanIsNotAFactoryException例外を

  3. 呼び出し側が取得する場合FactoryBeanの参照を、そしてbeanInstanceあるFactoryBean直接当時、(裁判官の前で)beanInstance

  4. 入ってくる場合はbeanInstance通常の豆、直接リターンbeanInstance

  5. これからすることでFactoryBean対応するBeanを作成します

おすすめ

転載: juejin.im/post/5d882369f265da03ec2ea191