欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

struts2_源码学习_factories

程序员文章站 2022-06-15 14:17:12
...

在ContainerBuilder和Container中最重要的一个字段就是: 

    final Map<Key<?>, InternalFactory<?>> factories;

从字面上我们可以看出这应该是对应的工厂键值对映射,那么key和value分别存储的是什么呢?

package com.opensymphony.xwork2.inject;

class Key<T> {
    final Class<T> type;
    final String name;
    final int hashCode;

    private Key(Class<T> type, String name) {
        if (type == null) {
            throw new NullPointerException("Type is null.");
        } else if (name == null) {
            throw new NullPointerException("Name is null.");
        } else {
            this.type = type;
            this.name = name;
            this.hashCode = type.hashCode() * 31 + name.hashCode();
        }
    }

    Class<T> getType() {
        return this.type;
    }

    String getName() {
        return this.name;
    }

    public int hashCode() {
        return this.hashCode;
    }

    public boolean equals(Object o) {
        if (!(o instanceof Key)) {
            return false;
        } else if (o == this) {
            return true;
        } else {
            Key other = (Key)o;
            return this.name.equals(other.name) && this.type.equals(other.type);
        }
    }

    public String toString() {
        return "[type=" + this.type.getName() + ", name='" + this.name + "']";
    }

    static <T> Key<T> newInstance(Class<T> type, String name) {
        return new Key(type, name);
    }
}

 可以看出Key存储的应该就是<bean>结点中对应的type和name属性。

package com.opensymphony.xwork2.inject;

import java.io.Serializable;

interface InternalFactory<T> extends Serializable {
    T create(InternalContext var1);

    Class<? extends T> type();
}

而InternalFactory则是一个接口,create()方法应该就是创建一个新的实例,我们需要去看它具体应用的地方。<bean>信息的传递过程应该是从 providers(register) -> builder(create) -> container(new ContainerBuilder)

以StrutsXmlConfigurationProvider为例,它的register方法在父类XmlConfigurationProvider中:

XmlConfigurationProvider.register()

public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
        LOG.trace("Parsing configuration file [{}]", this.configFileName);
        Map<String, Node> loadedBeans = new HashMap();
        Iterator i$ = this.documents.iterator();

        while(i$.hasNext()) {
            Document doc = (Document)i$.next();
            Element rootElement = doc.getDocumentElement();
            NodeList children = rootElement.getChildNodes();
            int childSize = children.getLength();

            for(int i = 0; i < childSize; ++i) {
                Node childNode = children.item(i);
                if (childNode instanceof Element) {
                    Element child = (Element)childNode;
                    String nodeName = child.getNodeName();
                    String type;
                    String name;
                    if ("bean".equals(nodeName)) {
                        type = child.getAttribute("type");
                        name = child.getAttribute("name");
                        String impl = child.getAttribute("class");
                        String onlyStatic = child.getAttribute("static");
                        String scopeStr = child.getAttribute("scope");
                        boolean optional = "true".equals(child.getAttribute("optional"));
                        Scope scope = Scope.SINGLETON;
                        if ("prototype".equals(scopeStr)) {
                            scope = Scope.PROTOTYPE;
                        } else if ("request".equals(scopeStr)) {
                            scope = Scope.REQUEST;
                        } else if ("session".equals(scopeStr)) {
                            scope = Scope.SESSION;
                        } else if ("singleton".equals(scopeStr)) {
                            scope = Scope.SINGLETON;
                        } else if ("thread".equals(scopeStr)) {
                            scope = Scope.THREAD;
                        }

                        if (StringUtils.isEmpty(name)) {
                            name = "default";
                        }

                        try {
                            Class classImpl = ClassLoaderUtil.loadClass(impl, this.getClass());
                            Class classType = classImpl;
                            if (StringUtils.isNotEmpty(type)) {
                                classType = ClassLoaderUtil.loadClass(type, this.getClass());
                            }

                            if ("true".equals(onlyStatic)) {
                                classImpl.getDeclaredClasses();
                                containerBuilder.injectStatics(new Class[]{classImpl});
                            } else {
                                if (containerBuilder.contains(classType, name)) {
                                    Location loc = LocationUtils.getLocation(loadedBeans.get(classType.getName() + name));
                                    if (this.throwExceptionOnDuplicateBeans) {
                                        throw new ConfigurationException("Bean type " + classType + " with the name " + name + " has already been loaded by " + loc, child);
                                    }
                                }

                                classImpl.getDeclaredConstructors();
                                LOG.debug("Loaded type: {} name: {} impl: {}", type, name, impl);
                                containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);
                            }

                            loadedBeans.put(classType.getName() + name, child);
                        } catch (Throwable var23) {
                            ...
                            }

                            LOG.debug("Unable to load optional class: {}", impl);
                        }
                    } else if ("constant".equals(nodeName)) {
                            ...
                        }

                        props.setProperty(type, name, childNode);
                    } else if (nodeName.equals("unknown-handler-stack")) {
                            ...
                    }
                }
            }
        }

    }

首先就是对<bean>结点信息进行解析,主要的信息type\name\class\scope等。然后调用:

containerBuilder.factory(classType, name, new LocatableFactory(name, classType, classImpl, scope, childNode), scope);

对于LocatableFactory不加以解释,暂时理解为工厂。scope就是范围的意思。

    public <T> ContainerBuilder factory(final Class<T> type, final String name, final Factory<? extends T> factory, Scope scope) {
        InternalFactory<T> internalFactory = new InternalFactory<T>() {
            public T create(InternalContext context) {
                try {
                    Context externalContext = context.getExternalContext();
                    return factory.create(externalContext);
                } catch (Exception var3) {
                    throw new RuntimeException(var3);
                }
            }

            public Class<? extends T> type() {
                return factory.type();
            }

            public String toString() {
                return (new LinkedHashMap<String, Object>() {
                    {
                        this.put("type", type);
                        this.put("name", name);
                        this.put("factory", factory);
                    }
                }).toString();
            }
        };
        return this.factory(Key.newInstance(type, name), internalFactory, scope);
    }

终于看到了InternalFactory的实现了,其中create方法主要就是为工厂注入一个上下环境,我们进入create方法看看:

 LocatableFactory

   public T create(Context context) {
        Object obj = context.getContainer().inject(this.implementation);
        return obj;
    }

这个我们在Container中提到过:inject()创建一个类的实例并进行对象的依赖注入操作。

那么接下来到了另外一个factory方法

  return this.factory(Key.newInstance(type, name), internalFactory, scope);

   private <T> ContainerBuilder factory(Key<T> key, InternalFactory<? extends T> factory, Scope scope) {
        this.ensureNotCreated();
        this.checkKey(key);
        InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);
        this.factories.put(key, scopedFactory);
        InternalFactory<T> callableFactory = this.createCallableFactory(key, scopedFactory);
        if (EarlyInitializable.class.isAssignableFrom(factory.type())) {
            this.earlyInitializableFactories.add(callableFactory);
        } else if (scope == Scope.SINGLETON) {
            this.singletonFactories.add(callableFactory);
        }

        return this;
    }

InternalFactory又会被再次加工:

 InternalFactory<? extends T> scopedFactory = scope.scopeFactory(key.getType(), key.getName(), factory);
Scope

    SINGLETON {
        <T> InternalFactory<? extends T> scopeFactory(Class<T> type, String name, final InternalFactory<? extends T> factory) {
            return new InternalFactory<T>() {
                T instance;

                public T create(InternalContext context) {
                    synchronized(context.getContainer()) {
                        if (this.instance == null) {
                            this.instance = InitializableFactory.wrapIfNeeded(factory).create(context);
                        }

                        return this.instance;
                    }
                }

                public Class<? extends T> type() {
                    return factory.type();
                }

                public String toString() {
                    return factory.toString();
                }
            };
        }
    },

Scope是一个枚举类型,为工厂添加一个作用的范围,我们可以看到其中的SINGLETON也就是单例模式,返回的就是一个单例模式的工厂。这就是factories中存储的value的值了

struts2_源码学习_factories

相关标签: struts2 factory