Spring学习之FacotryBean

1. BeanFacotry 与 FacotryBean以及FacotryBean是什么?

在spring中BeanFacotry是容器的顶层接口,定义着容器管理Bean的基础接口,我们在使用的使用一般不直接使用BeanFactory,而是使用下层的接口,诸如ApplicationContext等, 也就是我们常说的Spring的bean容器。

The FactoryBean interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.

这段官方文档也就说FactoryBean是用Spring提供给我们的扩展接口,当我们有复杂的Bean的初始化逻辑, 换言之我们bean的初始过程很复杂,并且我们又可以用代码很好的来实现bean的初始逻辑而不是用冗长的xml配置方式,那么我们就可以实现FactoryBean接口。

Tips: 本文的例子同时可以使用AOP或者使用BeanPostProcessor实现功能,只为展示FacotryBean的使用法

2. FactoryBean实战

注: 以下例子目的只为展示FactoryBean的使用方法。
现在我们有一个CarService接口, 并且有两个实现类AudiService和BmwService, 如下:

package com.example.factorybeantest.service;

public interface CarService {
    void carName();

    void carColor();

    default void desc() {
        this.carName();
        this.carColor();
        System.out.println("开始开车。。。。");
    }
}
package com.example.factorybeantest.service;

public class AudiCarService implements CarService {
    @Override
    public void carName() {
        System.out.println("这是一个奥迪车");
    }

    @Override
    public void carColor() {
        System.out.println("这是一个黑色的奥迪车");
    }
}
package com.example.factorybeantest.service;

public class BMWCarService implements CarService {
    @Override
    public void carName() {
        System.out.println("这是一个BMW车");
    }

    @Override
    public void carColor() {
        System.out.println("这是一个黑色的BMW车");
    }
}

现在我们需要根据配置把CarServiceBean注入到Bean工厂,并且需要对该对象所有的方法进行增强。对方法的增强我们可以直接使用AOP编程,但是在这里我们直接使用动态代理实现。现在我们实现一个CarServiceFactoryBean

package com.example.factorybeantest.factory;

import com.example.factorybeantest.service.CarService;
import org.springframework.beans.factory.FactoryBean;

/**
 * CAR 工厂Bean
 *
 * @author Elvis
 * @version 1.0, 2022/11/24
 */
public class CarServiceFactoryBean implements FactoryBean<CarService> {
    private CarService carService;

    public CarServiceFactoryBean(CarService carService) {
        this.carService = carService;
    }

    @Override
    public CarService getObject() throws Exception {
        return carService;
    }

    @Override
    public Class<?> getObjectType() {
        return carService.getClass();
    }
}

然后我们添加一个配置类,把当前的FactoryBean注入到Spring容器中:

package com.example.factorybeantest.config;

import com.example.factorybeantest.factory.CarServiceFactoryBean;
import com.example.factorybeantest.proxy.CarServiceInvocationHandler;
import com.example.factorybeantest.service.CarService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Proxy;

/**
 * 配置类
 */
@Configuration
@ComponentScan(basePackages = {"com.example.factorybeantest"})
public class Config {

    @Value("${car.className:com.example.factorybeantest.service.AudiCarService}")
    private String className;


    @Bean
    public CarServiceFactoryBean carService() throws Exception {
        Class<?> clazz = Class.forName(className);
        // 使用动态代理对Bean的方法进行增强处理
        Object obj = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
                new CarServiceInvocationHandler((CarService) clazz.getDeclaredConstructor().newInstance()));
        return new CarServiceFactoryBean((CarService) obj);
    }
}
package com.example.factorybeantest.proxy;

import com.example.factorybeantest.service.CarService;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 *
 *
 * @author Elvis
 */
public class CarServiceInvocationHandler implements InvocationHandler {
    private CarService carService;

    public CarServiceInvocationHandler(CarService carService) {
        this.carService = carService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("给Car加油");
        Object result = method.invoke(carService, args);
        System.out.println("给Car洗车");
        return result;
    }
}

编写测试类对FacotryBean进行测试:

package com.example.factorybeantest;

import com.example.factorybeantest.config.Config;
import com.example.factorybeantest.factory.CarServiceFactoryBean;
import com.example.factorybeantest.service.AudiCarService;
import com.example.factorybeantest.service.BMWCarService;
import com.example.factorybeantest.service.CarService;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;


class FactoryBeanTestApplicationTests  {

    private static ApplicationContext applicationContext;

    static  {
        applicationContext = new AnnotationConfigApplicationContext(Config.class);
    }


    @Test
    public void testBean() {
    	  /**
           When you need to ask a container for an actual FactoryBean instance itself instead of the 	bean it produces,
           prefix the bean’s id with the ampersand symbol (&) when calling the getBean() method of the
           ApplicationContext. So, for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container
           returns the product of the FactoryBean, whereas invoking getBean("&myBean") returns the FactoryBean instance itself.
         */
    	// 当我们需要使用工厂Bean本身的时候,需要在beanName前加上“&”
        CarServiceFactoryBean factoryBean = (CarServiceFactoryBean) applicationContext.getBean("&carService");
        System.out.println(factoryBean);
        System.out.println("===================");
        CarService carService = (CarService) applicationContext.getBean("carService");
        carService.desc();

    }
}

执行结果如下:

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值