netty的反射工厂模式

在看 netty 的反射工厂之前,我们先来看一下实际业务项目中,工厂模式是如何使用的。类图交互关系如下图:

实际业务开发可能会用到 Spring 框架,Spring提供了两个特别的接口:ApplicationContextAwareInitializingBean

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

BeanFactory 是根接口,也就是我们熟知的管理Bean的工厂,ListableBeanFactory 进一步继承了 BeanFactory,提供了如下一个方法:

    <T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException;

该方法可以根据类型获取对应的Bean实例。

ApplicationContext 继承的众多接口之一,就是继承了 ListableBeanFactoryApplicationContext 也称作是 Spring 上下文。这样来看,文章开头的代码就是将 Spring 上下文注入,也就是注入到我们的 TaskManagerFactory


另一个 Spring 接口 InitializingBean,只要实现了该接口的 Bean(我们的 TaskFactory 就通过注解配置成了一个 Bean,比如 @Component),就会在属性初始化之后调用

void afterPropertiesSet() throws Exception;

所以经过上述两个接口的方法设置,我们就成功的在 TaskManagerFactory 初始化的时候将实现了 TaskManager 接口的两个对象:TaskManagerImplATaskManagerImplB 添加到了 TaskManagerFactory 的 Map 中。

使用者是需要注入 TaskManagerFactory ,并调用 getTaskManger 方法即可。如果要新增一个 任务处理器,只需要在枚举类中添加数值,然后新建一个 TaskManager 的实现即可。


我们常见的例子是工厂类的get方法中,会通过 if else 判断要获取哪个对象,然后实力化后返回。本质上和上面的案例差不多。

那么 netty 上面是如何运用工厂模式,有什么特别的呢?

反射,没错就是用反射的方法来解耦。反射损耗性能x x x,不过不能脱离环境,我们来看经典的 echo server 代码。

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        final EchoServerHandler serverHandler = new EchoServerHandler();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
              // 方法内部创建反射工厂
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG, 100)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     p.addLast(serverHandler);
                 }
             });

            // 方法内部使用反射工厂创建 ServerSocketChannel 对象
            ChannelFuture f = b.bind(PORT).sync();

其中,.channel(NioServerSocketChannel.class) 方法内部实现为:

// 这里的 C 就是 Channel 接口   
public B channel(Class<? extends C> channelClass) {
        return channelFactory(new ReflectiveChannelFactory<C>(
                ObjectUtil.checkNotNull(channelClass, "channelClass")
        ));
}

执行完之后,就是将这个实力化的反射工厂对象 ReflectiveChannelFactory 作为成员变量设置到了 ServerBootstrap中。

NioServerSocketChannel 就是 Channel 接口的一种实现类,另外的实现类有 EpollServerSocketChannelOioServerSocketChannel(@Deprecated) 等。

new ReflectiveChannelFactory 时,我们看下内部实现:

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {
    private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } 
      ...
    }
}

可见,创建反射工厂时,就已经将 NioServerSocketChannel 的构造器设置进去了。


那么当程序执行 b.bind(PORT).sync(); 这条语句时,我们看下 bind 内部是如何利用之前设置的构造器的?

// bind内部调用的一个方法    
final ChannelFuture initAndRegister() {
        Channel channel = null;
        try {
          // 这一步调用方法
            channel = channelFactory.newChannel();
            init(channel);
        }
}

channelFactory.newChannel(); 这句的 channelFactory 就是之前初始化进去的。然后 newChannel 方法如下:

    public T newChannel() {
        try {
            return constructor.newInstance();
        }
    }

可见,直接利用了上面注入的 constructor,也就是 NioServerSocketChannel 类的构造器来创建具体对象的。


这样的好处是,当我们想要新增一个新的channel类型时,比如新增 KQueueServerSocketChannel ,只需要开发这个新的channel实现,然后在 echoServer 里面修改一条语句(这里先忽略上面的 EventLoopGroup 的修改):

//将
.channel(NioServerSocketChannel.class)
//修改为:
.channel(KQueueServerSocketChannel.class)  

满足开闭原则。


netty 追求高性能,而反射可能会降低性能,二者矛盾吗?不矛盾,这里的 ServerSocketChannel 相当于是服务器初始化过程中监听的channel,而不是每个连接接入时建立的 channel。对性能没有影响,且应用和维护起来简单。

既然如此,反射工厂模式和文章开头的案例能互换吗?可以,但是看从什么角度考量。


最后,再简单回顾下抽象工厂模式。抽象工厂相当于建立对工厂的抽象,客户端通过实力化不同的工厂,来创建不同种类的对象。如果理解了工厂模式,就可以把抽象工厂当作是工厂模式之上的对工厂的又一层封装。也就不必记忆产品簇产品种类什么的。

感兴趣的可以看看 netty 的源码,简单追踪下即可理解反射工厂的应用,从而对这类设计模式理解更加深刻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oatlmy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值