FactoryBean 实现接口代理

FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。

一、自定义 FactoryBean 重写 getObject方法 (通过动态代理生成对应接口的实现类)

/**
 * 接口实例工厂,这里主要是用于提供接口的实例对象
 * @author lichuang
 * @param <T>
 */
public class ServiceFactory<T> implements FactoryBean<T> {
 
    private Class<T> interfaceType;
 
    public ServiceFactory(Class<T> interfaceType) {
    this.interfaceType = interfaceType;
}

    @Override
    public T getObject() throws Exception {
        //这里主要是创建接口对应的实例,便于注入到spring容器中
        //ServiceProxy 为代理实现 具体见 jdk动态代理
        InvocationHandler handler = new ServiceProxy<>(interfaceType);
        return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(),
                new Class[] {interfaceType},handler);
    }

    @Override
    public Class<T> getObjectType() {
        return interfaceType;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

二、调用invoke 方法生成代理类(具体见jdk动态代理写法)

/**
 * 动态代理,需要注意的是,这里用到的是JDK自带的动态代理,代理对象只能是接口,不能是类
 * @author lichuang
 */
 
public class ServiceProxy<T> implements InvocationHandler {
 
    private Class<T> interfaceType;
 
    public ServiceProxy(Class<T> intefaceType) {
        this.interfaceType = interfaceType;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this,args);
        }
        Annotation[] annotations1=  method.getDeclaredAnnotations();
        for (Annotation annotation : annotations1) {
            System.out.println("方法注解:"+annotation.toString());
        }
        Annotation[][] annotations= method.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            System.out.println("-------------------------"+args[i].toString());
            for (Annotation annotation1 : annotations[i]) {
                System.out.println("参数注解:"+ annotation1.toString());
            }
        }
        System.out.println("调用前,参数:{}" + Arrays.toString(args));
        //这里可以得到参数数组和方法等,可以通过反射,注解等,进行结果集的处理
        //mybatis就是在这里获取参数和相关注解,然后根据返回值类型,进行结果集的转换
        Object result ="77777777777777777777777777777777";
        System.out.println("调用后,结果:{}" + result);
        return result;
    }
}

动态代理时也可以拿到方法的注解和参数的注解,通过这些注解可以做一些业务方面的问题。

三、注入BeanDefinition

/**
 * 用于Spring动态注入自定义接口
 *
 * @author lichuang
 */
@Component
public class ServiceBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor, ResourceLoaderAware, ApplicationContextAware {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //这里一般我们是通过反射获取需要代理的接口的clazz列表
        //比如判断包下面的类,或者通过某注解标注的类等等
		//1、扫描要被实现的接口
        Set<Class<?>> beanClazzs = scannerPackages("com.example.yuanmayuedu.service");
        for (Class beanClazz : beanClazzs) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClazz);
            GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();

            //在这里,我们可以给该对象的属性注入对应的实例。
            //比如mybatis,就在这里注入了dataSource和sqlSessionFactory,
            // 注意,如果采用definition.getPropertyValues()方式的话,
            // 类似definition.getPropertyValues().add("interfaceType", beanClazz);
            // 则要求在FactoryBean(本应用中即ServiceFactory)提供setter方法,否则会注入失败
            // 如果采用definition.getConstructorArgumentValues(),
            // 则FactoryBean中需要提供包含该属性的构造方法,否则会注入失败
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClazz);

            //注意,这里的BeanClass是生成Bean实例的工厂,不是Bean本身。
            // FactoryBean是一种特殊的Bean,其返回的对象不是指定类的一个实例,
            // 其返回的是该工厂Bean的getObject方法所返回的对象。
            //2、在bean定义里面设置 FactoryBean 即上述 ServiceFactory(spring 会根据 getObject 方法生成代理类bean)
            definition.setBeanClass(ServiceFactory.class);

            //这里采用的是byType方式注入,类似的还有byName等
            definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_NAME);
            //3、将bean 定义 注入到 注册器里
            registry.registerBeanDefinition(beanClazz.getSimpleName(), definition);
        }
    }

四、这个是将要被代理的接口(在 com.example.yuanmayuedu.service 包下)

public interface CalculateService {
    @Addressing
    String getResult(@Deprecated String name, @Deprecated @WebParam String a);
}

五、启动spring 测试

@SpringBootApplication
public class YuanmayueduApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context= SpringApplication.run(YuanmayueduApplication.class, args);
        CalculateService calculateService=  context.getBean(CalculateService.class);
        calculateService.getResult("张三","王五");

    }

}

六、测试结果

在这里插入图片描述

还没有读过 Fegin 和mybatis 的源码,不过本人猜想,实现思路应该差不多。通过此方法也可以自己实现远程调用等工具。。。。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
FactoryBean 可以用来创建任意接口代理类。具体实现方式如下: 1. 创建一个实现 FactoryBean 接口的类,例如 MyFactoryBean。 2. 在 MyFactoryBean 类中,实现 getObject() 方法,该方法返回一个代理对象,该代理对象可以代理任意接口。 3. 在 MyFactoryBean 类中,实现 getObjectType() 方法,该方法返回代理对象的类型。 4. 在 Spring 配置文件中,使用 <bean> 标签配置 MyFactoryBean 类。 5. 在 <bean> 标签中,使用 factory-bean 属性指定 MyFactoryBean 类,使用 factory-method 属性指定 getObject() 方法。 6. 在 <bean> 标签中,使用 <property> 标签注入需要代理接口,使用 name 属性指定属性名,使用 value 属性指定接口的全限定名。 示例代码如下: ``` public class MyFactoryBean implements FactoryBean<Object> { private Class<?> interfaceType; public void setInterfaceType(Class<?> interfaceType) { this.interfaceType = interfaceType; } @Override public Object getObject() throws Exception { InvocationHandler handler = new MyInvocationHandler(); return Proxy.newProxyInstance(interfaceType.getClassLoader(), new Class<?>[]{interfaceType}, handler); } @Override public Class<?> getObjectType() { return interfaceType; } @Override public boolean isSingleton() { return true; } } public class MyInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 实现代理逻辑 return null; } } <bean id="myFactoryBean" class="com.example.MyFactoryBean"> <property name="interfaceType" value="com.example.MyInterface"/> </bean> <bean id="myInterfaceProxy" factory-bean="myFactoryBean" factory-method="getObject"/> ``` 在以上示例代码中,MyFactoryBean 类实现FactoryBean 接口,重写了 getObject() 方法和 getObjectType() 方法,用于创建代理对象。MyInvocationHandler 类实现了 InvocationHandler 接口,用于实现代理逻辑。在 Spring 配置文件中,使用 <bean> 标签配置 MyFactoryBean 类,并使用 <property> 标签注入需要代理接口。最后,在 <bean> 标签中,使用 factory-bean 属性指定 MyFactoryBean 类,使用 factory-method 属性指定 getObject() 方法,即可获取代理对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值