From 9cfbcaba663c313b76476ea0e8c4c5eb870f079e Mon Sep 17 00:00:00 2001 From: aoshiguchen <1052045476@qq.com> Date: Sat, 2 Jul 2022 19:24:11 +0800 Subject: [PATCH] =?UTF-8?q?bean=E5=AE=B9=E5=99=A8=E9=87=8D=E6=9E=84ing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asgc/neutrino/core/annotation/Lazy.java | 2 +- .../core/bean/AbstractBeanFactory.java | 419 ++++++++++++++++++ .../asgc/neutrino/core/bean/BeanFactory.java | 84 ++++ .../asgc/neutrino/core/bean/BeanIdentity.java | 93 ++++ .../asgc/neutrino/core/bean/BeanRegistry.java | 84 ++++ .../asgc/neutrino/core/bean/BeanStatus.java | 55 +++ .../Bean.java => bean/BeanWrapper.java} | 57 +-- .../asgc/neutrino/core/bean/ClassScanner.java | 40 ++ .../fun/asgc/neutrino/core/bean/Identity.java | 43 ++ .../neutrino/core/bean/SimpleBeanFactory.java | 97 ++++ .../core/container/ApplicationContainer.java | 2 - .../core/container/BeanContainer.java | 10 +- .../neutrino/core/container/Container.java | 2 + .../DefaultApplicationContainer.java | 2 +- .../core/container/DefaultBeanContainer.java | 26 +- .../core/context/ApplicationContext.java | 105 ++++- .../{container => context}/LifeCycle.java | 2 +- .../core/context/LifeCycleManager.java | 69 +++ .../core/context/LifeCycleStatus.java | 42 ++ .../core/exception/BeanException.java | 39 ++ .../core/exception/InternalException.java | 3 + .../core/launcher/NeutrinoLauncher.java | 11 +- .../fun/asgc/neutrino/core/util/Assert.java | 6 + .../asgc/neutrino/core/util/BeanManager.java | 10 +- .../neutrino/core/util/CollectionUtil.java | 23 + .../asgc/neutrino/core/util/FunctionUtil.java | 54 +++ .../java/fun/asgc/neutrino/core/aop/Dog.java | 6 + .../fun/asgc/neutrino/core/aop/Test1.java | 6 + .../neutrino/core/bean/BeanIdentityTest.java | 51 +++ 29 files changed, 1385 insertions(+), 58 deletions(-) create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanFactory.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanIdentity.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanRegistry.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanStatus.java rename neutrino-core/src/main/java/fun/asgc/neutrino/core/{context/Bean.java => bean/BeanWrapper.java} (82%) create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/ClassScanner.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/Identity.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java rename neutrino-core/src/main/java/fun/asgc/neutrino/core/{container => context}/LifeCycle.java (96%) create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleManager.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleStatus.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/BeanException.java create mode 100644 neutrino-core/src/main/java/fun/asgc/neutrino/core/util/FunctionUtil.java create mode 100644 neutrino-core/src/test/java/fun/asgc/neutrino/core/bean/BeanIdentityTest.java diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/annotation/Lazy.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/annotation/Lazy.java index 39592627..0cb6ea9e 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/annotation/Lazy.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/annotation/Lazy.java @@ -35,5 +35,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Lazy { - + boolean value() default true; } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java new file mode 100644 index 00000000..201e07fa --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/AbstractBeanFactory.java @@ -0,0 +1,419 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.context.LifeCycle; +import fun.asgc.neutrino.core.context.LifeCycleManager; +import fun.asgc.neutrino.core.context.LifeCycleStatus; +import fun.asgc.neutrino.core.exception.BeanException; +import fun.asgc.neutrino.core.util.Assert; +import fun.asgc.neutrino.core.util.CollectionUtil; +import fun.asgc.neutrino.core.util.LockUtil; +import fun.asgc.neutrino.core.util.TypeUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 抽象的bean工厂 + * @author: aoshiguchen + * @date: 2022/7/1 + */ +@Slf4j +public abstract class AbstractBeanFactory implements BeanFactory, BeanRegistry, LifeCycle { + /** + * 父工厂 + */ + private AbstractBeanFactory parent; + /** + * bean缓存 + */ + protected Map beanCache; + /** + * 互斥锁 + */ + private Object mutex; + /** + * 名称 + */ + private String name; + /** + * 生命周期管理 + */ + private LifeCycleManager lifeCycleManager = LifeCycleManager.create(); + + public AbstractBeanFactory(String name) { + this(null, name); + } + + public AbstractBeanFactory(AbstractBeanFactory parent, String name) { + Assert.notNull(name, "工厂名称不能为空"); + this.parent = parent; + this.beanCache = new ConcurrentHashMap<>(256); + this.name = name; + if (null == parent) { + this.mutex = new Object(); + } else { + this.mutex = parent.getMutex(); + } + this.registerBean(this, this.name); + } + + @Override + public T getBean(String name, Object... args) throws BeanException { + Assert.notEmpty(name, "Bean名称不能为空!"); + T bean = (null == parent) ? null : parent.getBean(name, args); + return null != bean ? bean : doGetBean(name, args); + } + + @Override + public T getBean(Class type, Object... args) throws BeanException { + Assert.notNull(type, "Bean类型不能为空!"); + T bean = (null == parent) ? null : parent.getBean(type, args); + return null != bean ? bean : doGetBean(type, args); + } + + @Override + public T getBeanByTypeAndName(Class type, String name, Object... args) throws BeanException { + Assert.notEmpty(name, "Bean名称不能为空!"); + Assert.notNull(type, "Bean类型不能为空!"); + T bean = (null == parent) ? null : parent.getBeanByTypeAndName(type, name, args); + return null != bean ? bean : doGetBeanByNameAndType(name, type, args); + } + + @Override + public T getBean(BeanIdentity identity, Object... args) throws BeanException { + Assert.notNull(identity, "Bean的身份标识不能为空!"); + return (T)getBeanByTypeAndName(identity.getType(), identity.getName(), args); + } + + @Override + public List getBeanList(Class type, Object... args) throws BeanException { + return CollectionUtil.addAll(() -> new LinkedList<>(), + null == parent ? null : parent.getBeanList(type, args), + doGetBeanList(type, args) + ); + } + + @Override + public boolean hasBean(Class type, String name) { + boolean res = (null != parent) ? parent.hasBean(type, name) : false; + return res || doHasBean(type, name); + } + + @Override + public int countBean(String name) { + int count = (null != parent) ? parent.countBean(name) : 0; + return count + doCountBean(name); + } + + @Override + public int countBean(Class type) { + int count = (null != parent) ? parent.countBean(type) : 0; + return count + doCountBean(type); + } + + @Override + public void registerBean(Object obj) throws BeanException { + Assert.notNull(obj, "被注册的bean实例不能为空!"); + String name = TypeUtil.getDefaultVariableName(obj.getClass()); + registerBean(obj, name); + } + + /** + * 手动new出来的bean注册进来,视为已经初始化了 + * @param obj + * @param name + * @throws BeanException + */ + @Override + public void registerBean(Object obj, String name) throws BeanException { + Assert.notNull(obj, "被注册的bean实例不能为空!"); + Assert.notNull(obj, "被注册的bean名称不能为空!"); + synchronized (mutex) { + if (hasBean(obj.getClass(), name)) { + throw new BeanException(String.format("Bean[type:%s name:%s] 已存在,不能重复注册!", obj.getClass().getName(), name)); + } + addBean(new BeanWrapper() + .setType(obj.getClass()) + .setName(name) + .setInstance(obj) + .setStatus(BeanStatus.INIT) + ); + } + } + + @Override + public void registerBean(Class type) throws BeanException { + registerBean(type, TypeUtil.getDefaultVariableName(type)); + } + + @Override + public void registerBean(Class type, String name) throws BeanException { + synchronized (mutex) { + if (hasBean(type, name)) { + throw new BeanException(String.format("Bean[type:%s name:%s] 已存在,不能重复注册!", type.getName(), name)); + } + addBean(type, name); + } + } + + private T doGetBean(String name, Object... args) throws BeanException { + List beanList = findBeanList(name); + if (CollectionUtil.isEmpty(beanList)) { + return null; + } else if (beanList.size() > 1) { + throw new BeanException(String.format("Bean[name:%s] 存在多个实例!", name)); + } + return getOrNew(beanList.get(0)); + } + + private T doGetBean(Class type, Object... args) throws BeanException { + List beanList = findBeanList(type); + if (CollectionUtil.isEmpty(beanList)) { + return null; + } else if (beanList.size() > 1) { + throw new BeanException(String.format("Bean[type:%s] 存在多个实例!", type)); + } + return getOrNew(beanList.get(0)); + } + + private T doGetBeanByNameAndType(String name, Class type, Object... args) throws BeanException { + BeanWrapper bean = findBean(type, name); + if (null == bean) { + return null; + } + return getOrNew(bean); + } + + private List doGetBeanList(Class type, Object... args) throws BeanException { + List beanList = findBeanList(type); + if (CollectionUtil.isEmpty(beanList)) { + return null; + } + return getOrNew(beanList); + } + + private boolean doHasBean(Class type, String name) { + return beanCache.containsKey(new BeanIdentity(name, type)); + } + + private int doCountBean(String name) { + return beanCache.keySet().stream().filter(e -> e.getName().equals(name)).collect(Collectors.counting()).intValue(); + } + + private int doCountBean(Class type) { + return beanCache.keySet().stream().filter(e -> type.isAssignableFrom(e.getType())).collect(Collectors.counting()).intValue(); + } + + public Object getMutex() { + return mutex; + } + + /** + * 查找bean + * @param name + * @return + */ + private List findBeanList(String name) { + Assert.notNull(name, "bean的名称不能为空!"); + List beanList = new LinkedList<>(); + for (BeanIdentity identity : beanCache.keySet()) { + if (identity.getName().equals(name)) { + beanList.add(beanCache.get(identity)); + } + } + return beanList; + } + + /** + * 查找bean + * @param type + * @return + */ + private List findBeanList(Class type) { + Assert.notNull(type, "bean的类型不能为空!"); + List beanList = new LinkedList<>(); + for (BeanIdentity identity : beanCache.keySet()) { + if (type.isAssignableFrom(identity.getType())) { + beanList.add(beanCache.get(identity)); + } + } + return beanList; + } + + /** + * 查找bean + * @param type + * @param name + * @return + */ + private BeanWrapper findBean(Class type, String name) { + Assert.notNull(type, "bean的类型不能为空!"); + Assert.notNull(name, "bean的名称不能为空!"); + return beanCache.get(new BeanIdentity(name, type)); + } + + /** + * 新增一个bean + * @param bean + */ + protected void addBean(BeanWrapper bean) { + beanCache.put(new BeanIdentity(bean.getName(), bean.getType()), bean); + } + + @Override + public void init() { + lifeCycleManager.init(() -> { + if (null != parent) { + parent.init(); + } + if (CollectionUtil.notEmpty(beanCache)) { + beanCache.values().stream().filter(b -> BeanStatus.INJECT == b.getStatus()).forEach(bean -> bean.init()); + } + log.info("bean工厂[{}]初始化.", getName()); + }); + } + + @Override + public void destroy() { + lifeCycleManager.destroy(() -> { + if (null != parent) { + parent.destroy(); + } + if (CollectionUtil.notEmpty(beanCache)) { + beanCache.values().stream().filter(b -> BeanStatus.DESTROY != b.getStatus()).forEach(bean -> bean.destroy()); + } + log.info("bean工厂[{}]销毁.", getName()); + }); + } + + /** + * 获取或创建实例 + * @param beanList + * @param + * @return + * @throws BeanException + */ + protected List getOrNew(List beanList) throws BeanException { + List list = new LinkedList<>(); + if (CollectionUtil.isEmpty(beanList)) { + return list; + } + for (BeanWrapper bean : beanList) { + T instance = getOrNew(bean); + if (null == instance) { + throw new BeanException(String.format("Bean[type:%s name:%s]实例化失败!", bean.getType().getName(), bean.getName())); + } + list.add(instance); + } + return list; + } + + /** + * 获取名称 + * @return + */ + public String getName() { + return name; + } + + /** + * 获取生命周期状态 + * @return + */ + public LifeCycleStatus getLifeCycleStatus() { + return lifeCycleManager.getStatus(); + } + + /** + * 获取生命周期管理对象 + * @return + */ + public LifeCycleManager getLifeCycleManager() { + return lifeCycleManager; + } + + /** + * 新增一个bean + * @param type + * @param name + */ + protected abstract void addBean(Class type, String name); + + /** + * 获取或创建实例 + * @param bean + * @param + * @return + */ + protected T getOrNew(BeanWrapper bean) throws BeanException { + return (T)LockUtil.doubleCheckProcess( + () -> !(BeanStatus.INIT == bean.getStatus() || BeanStatus.RUNNING == bean.getStatus()), + bean, + () -> { + if (BeanStatus.REGISTER == bean.getStatus()) { + dependencyCheck(bean); + } + if (BeanStatus.DEPENDENCY_CHECKING == bean.getStatus()) { + newInstance(bean); + } + if (BeanStatus.INSTANCE == bean.getStatus()) { + inject(bean); + } + if (BeanStatus.INJECT == bean.getStatus()) { + bean.init(); + } + }, + () -> bean.getInstance() + ); + } + + /** + * 依赖关系检测 + * @param bean + * @return + * @throws BeanException + */ + protected abstract boolean dependencyCheck(BeanWrapper bean) throws BeanException; + + /** + * 实例化 + * @param bean + * @param + * @return + * @throws BeanException + */ + protected abstract T newInstance(BeanWrapper bean) throws BeanException; + + /** + * 注入 + * @param bean + * @return + * @throws BeanException + */ + protected abstract boolean inject(BeanWrapper bean) throws BeanException; +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanFactory.java new file mode 100644 index 00000000..b106cd9a --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanFactory.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.exception.BeanException; + +import java.util.List; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public interface BeanFactory { + + /** + * 尝试根据名称获取bean + * @param name + * @param args + * @return + * @throws BeanException + */ + T getBean(String name, Object... args) throws BeanException; + + /** + * 尝试根据类型获取bean + * @param type + * @param args + * @param + * @return + * @throws BeanException + */ + T getBean(Class type, Object... args) throws BeanException; + + /** + * 尝试根据Bean身份标识获取bean + * @param identity + * @param args + * @param + * @return + * @throws BeanException + */ + T getBean(BeanIdentity identity, Object... args) throws BeanException; + + /** + * 根据类型+名称获取bean + * @param type + * @param name + * @param args + * @param + * @return + * @throws BeanException + */ + T getBeanByTypeAndName(Class type, String name, Object... args) throws BeanException; + + /** + * 尝试根据类型获取bean + * @param type + * @param args + * @param + * @return + * @throws BeanException + */ + List getBeanList(Class type, Object... args) throws BeanException; +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanIdentity.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanIdentity.java new file mode 100644 index 00000000..f1f30c24 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanIdentity.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.util.Assert; + +/** + * 用于标识bean的身份 + * + * 此处用名称+类型作为bean的唯一标识 + * + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public class BeanIdentity implements Identity { + /** + * 名称 + */ + private String name; + /** + * 类型 + */ + private Class type; + /** + * hashCode + */ + private int identityHashCode; + + public BeanIdentity(String name, Class type) { + Assert.notEmpty(name, "名称不能为空!"); + Assert.notNull(type, "类型不能为空!"); + this.name = name; + this.type = type; + this.identityHashCode = System.identityHashCode(name) + System.identityHashCode(type); + } + + /** + * 获取名称 + * @return + */ + public String getName() { + return this.name; + } + + /** + * 获取类型 + * @return + */ + public Class getType() { + return this.type; + } + + @Override + public boolean isOnly() { + return Boolean.TRUE; + } + + @Override + public boolean equals(Object obj) { + if (null == obj) { + return false; + } + if (!(obj instanceof BeanIdentity)) { + return false; + } + BeanIdentity beanIdentity = (BeanIdentity)obj; + return this.name.equals(beanIdentity.getName()) && this.type.equals(beanIdentity.getType()); + } + + @Override + public int hashCode() { + return identityHashCode; + } +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanRegistry.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanRegistry.java new file mode 100644 index 00000000..d8c2cdc7 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanRegistry.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.exception.BeanException; + +/** + * bean注册表 + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public interface BeanRegistry { + + /** + * 注册bean + * @param obj + * @throws BeanException + */ + void registerBean(Object obj) throws BeanException; + + /** + * 注册bean + * @param obj + * @param name + * @throws BeanException + */ + void registerBean(Object obj, String name) throws BeanException; + + /** + * 注册bean + * @param type + * @throws BeanException + */ + void registerBean(Class type) throws BeanException; + + /** + * 注册bean + * @param type + * @param name + * @throws BeanException + */ + void registerBean(Class type, String name) throws BeanException; + + /** + * 判断是否包含此bean + * @param type + * @param name + * @return + */ + boolean hasBean(Class type, String name); + + /** + * 查询bean容器中有多少个叫该名称的bean + * @param name + * @return + */ + int countBean(String name); + + /** + * 查询bean容器中有多少个该类型的bean + * @param type + * @return + */ + int countBean(Class type); +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanStatus.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanStatus.java new file mode 100644 index 00000000..5062f4b4 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanStatus.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Bean的几种状态 + * @author: aoshiguchen + * @date: 2022/7/2 + */ +@Getter +@AllArgsConstructor +public enum BeanStatus { + REGISTER(1, "已注册"), + DEPENDENCY_CHECKING(2, "依赖关系检测完成"), + INSTANCE(3, "已实例化"), + INJECT(4, "已完成注入"), + INIT(5, "已初始化"), + RUNNING(6, "运行中"), + DESTROY(7, "已销毁"); + private static final Map cache = Stream.of(BeanStatus.values()).collect(Collectors.toMap(BeanStatus::getStatus, Function.identity())); + + private Integer status; + private String desc; + + public static BeanStatus of(Integer status) { + return cache.get(status); + } +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Bean.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java similarity index 82% rename from neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Bean.java rename to neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java index 0ffcb62d..1dd203f9 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/Bean.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/BeanWrapper.java @@ -20,22 +20,23 @@ * SOFTWARE. */ -package fun.asgc.neutrino.core.context; +package fun.asgc.neutrino.core.bean; import fun.asgc.neutrino.core.annotation.*; import fun.asgc.neutrino.core.aop.Aop; -import fun.asgc.neutrino.core.container.LifeCycle; +import fun.asgc.neutrino.core.context.LifeCycle; import fun.asgc.neutrino.core.container.BeanContainer; +import fun.asgc.neutrino.core.context.ApplicationConfig; +import fun.asgc.neutrino.core.context.ApplicationContext; +import fun.asgc.neutrino.core.context.Environment; import fun.asgc.neutrino.core.util.*; import lombok.Data; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Set; -import java.util.stream.Stream; /** * @@ -45,14 +46,16 @@ import java.util.stream.Stream; @Slf4j @Accessors(chain = true) @Data -public class Bean implements LifeCycle { +public class BeanWrapper implements LifeCycle { private String name; - private Class clazz; + private Class type; private Object instance; private Component component; private int order; private boolean isBoot; private volatile boolean isInit; + private BeanStatus status; + private boolean isLazy; public boolean hasInstance() { return null != instance; @@ -68,14 +71,14 @@ public class Bean implements LifeCycle { } isInit = true; - Set methods = ReflectUtil.getMethods(clazz); + Set methods = ReflectUtil.getMethods(type); if (CollectionUtil.notEmpty(methods)) { for (Method method : methods) { if (method.isAnnotationPresent(Init.class) && method.getParameters().length == 0) { try { method.invoke(instance); } catch (Exception e) { - log.error(String.format("初始化方法执行异常 class:%s method:%s", clazz.getName(), method.getName()), e); + log.error(String.format("初始化方法执行异常 class:%s method:%s", type.getName(), method.getName()), e); } } } @@ -87,14 +90,14 @@ public class Bean implements LifeCycle { if (!hasInstance()) { return; } - Set methods = ReflectUtil.getMethods(clazz); + Set methods = ReflectUtil.getMethods(type); if (CollectionUtil.notEmpty(methods)) { for (Method method : methods) { if (method.isAnnotationPresent(Destroy.class) && method.getParameters().length == 0) { try { method.invoke(instance); } catch (Exception e) { - log.error(String.format("销毁方法执行异常 class:%s method:%s", clazz.getName(), method.getName()), e); + log.error(String.format("销毁方法执行异常 class:%s method:%s", type.getName(), method.getName()), e); } } } @@ -116,14 +119,14 @@ public class Bean implements LifeCycle { () -> { try { // 暂时先只支持yml配置 - Configuration configuration = clazz.getAnnotation(Configuration.class); + Configuration configuration = type.getAnnotation(Configuration.class); if (null != configuration) { - instance = ConfigUtil.getYmlConfig(clazz); - } else if (ClassUtil.isInterface(clazz)) { - instance = Aop.get(clazz); + instance = ConfigUtil.getYmlConfig(type); + } else if (ClassUtil.isInterface(type)) { + instance = Aop.get(type); } else { // 由编码规避没有无参构造器的问题 - instance = clazz.newInstance(); + instance = type.newInstance(); } } catch (Exception e) { // ignore @@ -134,7 +137,7 @@ public class Bean implements LifeCycle { } private void inject(ApplicationContext context) { - Set methods = ReflectUtil.getMethods(clazz); + Set methods = ReflectUtil.getMethods(type); if (CollectionUtil.notEmpty(methods)) { methods.stream().forEach(method -> { fun.asgc.neutrino.core.annotation.Bean bean = method.getAnnotation(fun.asgc.neutrino.core.annotation.Bean.class); @@ -153,8 +156,8 @@ public class Bean implements LifeCycle { log.error("bean 实例不能为空!"); return; } - context.getBeanContainer().addBean(new Bean() - .setClazz(obj.getClass()) + context.getBeanContainer().addBean(new BeanWrapper() + .setType(obj.getClass()) .setBoot(false) .setComponent(null) .setInstance(obj) @@ -167,7 +170,7 @@ public class Bean implements LifeCycle { } }); } - Set fieldSet = ReflectUtil.getInheritChainDeclaredFieldSet(clazz); + Set fieldSet = ReflectUtil.getInheritChainDeclaredFieldSet(type); if (CollectionUtil.notEmpty(fieldSet)) { fieldSet.forEach(field -> { Autowired autowired = field.getAnnotation(Autowired.class); @@ -184,17 +187,17 @@ public class Bean implements LifeCycle { ReflectUtil.setFieldValue(field, instance, context); } else { Class autowiredType = field.getType(); - Bean autowiredBean = null; + BeanWrapper autowiredBean = null; if (StringUtil.isEmpty(autowired.value())) { autowiredBean = context.getBeanContainer().getBean(autowiredType); } else { autowiredBean = context.getBeanContainer().getBean(autowired.value()); } if (null == autowiredBean) { - throw new RuntimeException(String.format("类 %s 自动装配字段:%s 依赖bean不存在!", clazz.getName(), field.getName())); + throw new RuntimeException(String.format("类 %s 自动装配字段:%s 依赖bean不存在!", type.getName(), field.getName())); } - if (autowiredBean.isDependOn(clazz)) { - throw new RuntimeException(String.format("类[%s]与类[%s]存在循环依赖!", clazz.getName(), field.getType().getName())); + if (autowiredBean.isDependOn(type)) { + throw new RuntimeException(String.format("类[%s]与类[%s]存在循环依赖!", type.getName(), field.getType().getName())); } autowiredBean.newInstance(context); ReflectUtil.setFieldValue(field, instance, autowiredBean.getInstance()); @@ -204,7 +207,7 @@ public class Bean implements LifeCycle { } public boolean isLazy() { - Lazy lazy = ClassUtil.getAnnotation(clazz, Lazy.class); + Lazy lazy = ClassUtil.getAnnotation(type, Lazy.class); return null != lazy; } @@ -212,7 +215,7 @@ public class Bean implements LifeCycle { if (null == target) { return false; } - Set fieldSet = ReflectUtil.getInheritChainDeclaredFieldSet(clazz); + Set fieldSet = ReflectUtil.getInheritChainDeclaredFieldSet(type); if (CollectionUtil.isEmpty(fieldSet)) { return false; } @@ -227,4 +230,8 @@ public class Bean implements LifeCycle { } return false; } + + public void run() { + + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/ClassScanner.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/ClassScanner.java new file mode 100644 index 00000000..32b52f2e --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/ClassScanner.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author: aoshiguchen + * @date: 2022/7/2 + */ +public class ClassScanner { + private Set> classes = new HashSet<>(); + private List scanBasePackages; + + public ClassScanner(List scanBasePackages) { + this.scanBasePackages = scanBasePackages; + } + +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/Identity.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/Identity.java new file mode 100644 index 00000000..2a77330e --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/Identity.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +/** + * Identity 用于标识一个身份。 + * + * 当`isOnly()`为true时,该标识是一个唯一标识。 + * + * 如:身份证、财富、年龄都可以作为人的身份象征,但只有身份证是唯一标识。 + * 这个唯一性取决与理论上的定义,而非实际数据。 + * 例如有三个人,年龄分别是18、19、20,此时对于这三人而言,年龄是唯一的,但年龄这个标识我们仍然认为是非唯一标识。 + * 除非在特定场景下,这些数据固定不变、或者确保以后新增的数据也不会打破这一设定。 + * + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public interface Identity { + /** + * 是否唯一标识 + * @return + */ + boolean isOnly(); +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java new file mode 100644 index 00000000..4d5717fb --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/bean/SimpleBeanFactory.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.annotation.Lazy; +import fun.asgc.neutrino.core.annotation.Order; +import fun.asgc.neutrino.core.exception.BeanException; +import fun.asgc.neutrino.core.runner.ApplicationRunner; +import fun.asgc.neutrino.core.util.ClassUtil; +import fun.asgc.neutrino.core.util.CollectionUtil; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author: 一个简单的bean工厂实现 + * @date: 2022/7/2 + */ +@Slf4j +public class SimpleBeanFactory extends AbstractBeanFactory { + + public SimpleBeanFactory(String name) { + super(name); + } + + public SimpleBeanFactory(AbstractBeanFactory parent, String name) { + super(parent, name); + } + + @Override + protected void addBean(Class type, String name) { + log.debug("addBean[type:{} name:{}]", type.getName(), name); + BeanWrapper beanWrapper = new BeanWrapper() + .setType(type) + .setName(name) + .setLazy(Boolean.FALSE) + .setOrder(Integer.MAX_VALUE) + .setStatus(BeanStatus.REGISTER); + Lazy lazy = ClassUtil.getAnnotation(type, Lazy.class); + if (null != lazy) { + beanWrapper.setLazy(lazy.value()); + } + Order order = ClassUtil.getAnnotation(type, Order.class); + if (null != order) { + beanWrapper.setOrder(order.value()); + } + addBean(beanWrapper); + } + + @Override + protected boolean dependencyCheck(BeanWrapper bean) throws BeanException { + return false; + } + + @Override + protected T newInstance(BeanWrapper bean) throws BeanException { + return null; + } + + @Override + protected boolean inject(BeanWrapper bean) throws BeanException { + return false; + } + + @Override + public void init() { + List beanWrapperList = beanCache.values().stream() + .filter(b -> b.getStatus().getStatus() < BeanStatus.INIT.getStatus()) + .filter(b -> ApplicationRunner.class.isAssignableFrom(b.getType()) || !b.isLazy() || b.getOrder() <= 0) + .collect(Collectors.toList()); + if (CollectionUtil.notEmpty(beanWrapperList)) { + getOrNew(beanWrapperList); + } + super.init(); + } +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/ApplicationContainer.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/ApplicationContainer.java index 12937029..f9ade5c6 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/ApplicationContainer.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/ApplicationContainer.java @@ -29,6 +29,4 @@ package fun.asgc.neutrino.core.container; */ public interface ApplicationContainer extends Container { - - } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/BeanContainer.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/BeanContainer.java index 0975eaa1..bafa1719 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/BeanContainer.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/BeanContainer.java @@ -22,7 +22,7 @@ package fun.asgc.neutrino.core.container; -import fun.asgc.neutrino.core.context.Bean; +import fun.asgc.neutrino.core.bean.BeanWrapper; import java.util.List; @@ -52,24 +52,24 @@ public interface BeanContainer extends Container { * @param clazz * @return */ - Bean getBean(Class clazz); + BeanWrapper getBean(Class clazz); /** * 获取bean实例 * @param name * @return */ - Bean getBean(String name); + BeanWrapper getBean(String name); /** * 获取bean集合 * @return */ - List beanList(); + List beanList(); /** * 添加bean * @param bean */ - void addBean(Bean bean); + void addBean(BeanWrapper bean); } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/Container.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/Container.java index b5b688f5..2b39e723 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/Container.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/Container.java @@ -22,6 +22,8 @@ package fun.asgc.neutrino.core.container; +import fun.asgc.neutrino.core.context.LifeCycle; + /** * * @author: aoshiguchen diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultApplicationContainer.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultApplicationContainer.java index da315fff..04e31fc7 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultApplicationContainer.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultApplicationContainer.java @@ -67,7 +67,7 @@ public class DefaultApplicationContainer implements ApplicationContainer { this.beanContainer.beanList().forEach(bean -> { if (bean.isBoot()) { if (bean.hasInstance()) { - if (ApplicationRunner.class.isAssignableFrom(bean.getClazz())) { + if (ApplicationRunner.class.isAssignableFrom(bean.getType())) { ApplicationRunner runner = (ApplicationRunner)bean.getInstance(); runner.run(environment.getMainArgs()); } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultBeanContainer.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultBeanContainer.java index 73a4536f..3865e9ee 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultBeanContainer.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/DefaultBeanContainer.java @@ -25,7 +25,7 @@ package fun.asgc.neutrino.core.container; import com.google.common.collect.Lists; import fun.asgc.neutrino.core.annotation.Component; import fun.asgc.neutrino.core.annotation.Order; -import fun.asgc.neutrino.core.context.Bean; +import fun.asgc.neutrino.core.bean.BeanWrapper; import fun.asgc.neutrino.core.cache.Cache; import fun.asgc.neutrino.core.cache.MemoryCache; import fun.asgc.neutrino.core.context.Environment; @@ -49,9 +49,9 @@ import java.util.List; public class DefaultBeanContainer implements BeanContainer { private Environment environment; private ClassContainer classContainer; - private Cache nameBeanCache; - private Cache, Bean> classBeanCache; - private List beans; + private Cache nameBeanCache; + private Cache, BeanWrapper> classBeanCache; + private List beans; public DefaultBeanContainer(Environment environment) { this.environment = environment; @@ -72,12 +72,12 @@ public class DefaultBeanContainer implements BeanContainer { } @Override - public Bean getBean(Class clazz) { + public BeanWrapper getBean(Class clazz) { return classBeanCache.get(clazz); } @Override - public Bean getBean(String name) { + public BeanWrapper getBean(String name) { return nameBeanCache.get(name); } @@ -96,8 +96,8 @@ public class DefaultBeanContainer implements BeanContainer { orderValue = order.value(); } - addBean(new Bean() - .setClazz(clazz) + addBean(new BeanWrapper() + .setType(clazz) .setName(name) .setComponent(component) .setOrder(orderValue) @@ -107,7 +107,7 @@ public class DefaultBeanContainer implements BeanContainer { if (!classBeanCache.isEmpty()) { beans = Lists.newArrayList(classBeanCache.values()); - Collections.sort(beans, Comparator.comparingInt(Bean::getOrder)); + Collections.sort(beans, Comparator.comparingInt(BeanWrapper::getOrder)); } log.info("bean容器初始化完成"); @@ -120,21 +120,21 @@ public class DefaultBeanContainer implements BeanContainer { } @Override - public void addBean(Bean bean) { + public void addBean(BeanWrapper bean) { if (null == bean) { return; } // TODO 暂时由编码时规避名字冲突 - if (ApplicationRunner.class.isAssignableFrom(bean.getClazz())) { + if (ApplicationRunner.class.isAssignableFrom(bean.getType())) { bean.setOrder(Integer.MIN_VALUE); bean.setBoot(true); } - classBeanCache.set(bean.getClazz(), bean); + classBeanCache.set(bean.getType(), bean); nameBeanCache.set(bean.getName(), bean); } @Override - public List beanList() { + public List beanList() { return beans; } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationContext.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationContext.java index dec51dbc..49d55a10 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationContext.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/ApplicationContext.java @@ -22,10 +22,22 @@ package fun.asgc.neutrino.core.context; +import fun.asgc.neutrino.core.annotation.Component; +import fun.asgc.neutrino.core.aop.interceptor.ExceptionHandler; +import fun.asgc.neutrino.core.aop.interceptor.Filter; +import fun.asgc.neutrino.core.aop.interceptor.Interceptor; +import fun.asgc.neutrino.core.aop.interceptor.ResultAdvice; +import fun.asgc.neutrino.core.bean.SimpleBeanFactory; import fun.asgc.neutrino.core.container.BeanContainer; -import fun.asgc.neutrino.core.util.StringUtil; +import fun.asgc.neutrino.core.runner.ApplicationRunner; +import fun.asgc.neutrino.core.util.*; import lombok.Data; import lombok.experimental.Accessors; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.List; +import java.util.Set; /** * @@ -34,7 +46,8 @@ import lombok.experimental.Accessors; */ @Accessors(chain = true) @Data -public class ApplicationContext { +@Slf4j +public class ApplicationContext implements LifeCycle { /** * 应用环境 @@ -48,4 +61,92 @@ public class ApplicationContext { * bean容器 */ private BeanContainer beanContainer; + /** + * 根Bean工厂 + */ + private SimpleBeanFactory rootBeanFactory; + /** + * bean工厂 + */ + private SimpleBeanFactory applicationBeanFactory; + /** + * 生命周期管理者 + */ + private LifeCycleManager lifeCycleManager = LifeCycleManager.create(); + + public ApplicationContext() { + + } + + public ApplicationContext(Environment environment) { + this.environment = environment; + } + + @Override + public synchronized void init() { + this.lifeCycleManager.init(() -> { + try { + this.rootBeanFactory = new SimpleBeanFactory("rootBeanFactory"); + this.applicationBeanFactory = new SimpleBeanFactory(rootBeanFactory, "applicationBeanFactory"); + this.rootBeanFactory.registerBean(environment, "rootEnvironment"); + this.rootBeanFactory.registerBean(this, "rootApplicationContext"); + this.rootBeanFactory.registerBean(environment.getConfig(), "rootApplicationConfig"); + register(); + this.applicationBeanFactory.init(); + // TODO 后面优化掉这种不安全的BeanManager + BeanManager.setContext(this); + } catch (Exception e) { + log.error("应用上下文初始化异常!", e); + System.exit(-1); + } + + log.info("应用上下文初始化完成"); + }); + } + + @Override + public void destroy() { + this.lifeCycleManager.destroy(() -> { + + this.applicationBeanFactory.destroy(); + log.info("应用上下文销毁"); + }); + } + + /** + * bean注册 + * 所有的拦截器默认都是bean组件,没带Component注解时,默认是延迟加载的 + */ + private void register() throws IOException, ClassNotFoundException { + Set> classes = ClassUtil.scan(environment.getScanBasePackages()); + if (CollectionUtil.isEmpty(classes)) { + return; + } + classes.stream() + .filter(item -> ClassUtil.isAnnotateWith(item, Component.class) + || Interceptor.class.isAssignableFrom(item) + || Filter.class.isAssignableFrom(item) + || ExceptionHandler.class.isAssignableFrom(item) + || ResultAdvice.class.isAssignableFrom(item) + ) + .forEach(clazz -> { + String beanName = TypeUtil.getDefaultVariableName(clazz); + Component component = ClassUtil.getAnnotation(clazz, Component.class); + if (null != component && StringUtil.notEmpty(component.value())) { + beanName = component.value(); + } + this.applicationBeanFactory.registerBean(clazz, beanName); + }); + } + + /** + * 应用上下文启动 + */ + public void run() { + init(); + List applicationRunnerList = this.applicationBeanFactory.getBeanList(ApplicationRunner.class); + if (CollectionUtil.notEmpty(applicationRunnerList)) { + applicationRunnerList.forEach(applicationRunner -> applicationRunner.run(this.environment.getMainArgs())); + } + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/LifeCycle.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycle.java similarity index 96% rename from neutrino-core/src/main/java/fun/asgc/neutrino/core/container/LifeCycle.java rename to neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycle.java index 72972d7a..fc03464a 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/container/LifeCycle.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycle.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package fun.asgc.neutrino.core.container; +package fun.asgc.neutrino.core.context; /** * diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleManager.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleManager.java new file mode 100644 index 00000000..c64cbc1b --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleManager.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.context; + +import fun.asgc.neutrino.core.base.CodeBlock; + +/** + * + * @author: 生命周期管理 + * @date: 2022/7/2 + */ +public class LifeCycleManager { + /** + * 生命周期状态 + */ + private LifeCycleStatus status; + + private LifeCycleManager() { + this.status = LifeCycleStatus.CREATE; + } + + public synchronized void init(CodeBlock codeBlock) { + if (this.status == LifeCycleStatus.CREATE) { + codeBlock.execute(); + this.status = LifeCycleStatus.INIT; + } + } + + public synchronized void run(CodeBlock codeBlock) { + if (this.status == LifeCycleStatus.INIT) { + codeBlock.execute(); + this.status = LifeCycleStatus.RUN; + } + } + + public synchronized void destroy(CodeBlock codeBlock) { + if (this.status != LifeCycleStatus.DESTROY) { + codeBlock.execute(); + this.status = LifeCycleStatus.DESTROY; + } + } + + public static LifeCycleManager create() { + return new LifeCycleManager(); + } + + public LifeCycleStatus getStatus() { + return status; + } +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleStatus.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleStatus.java new file mode 100644 index 00000000..64ef71be --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/context/LifeCycleStatus.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.context; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * + * @author: 生命周期状态 + * @date: 2022/7/2 + */ +@Getter +@AllArgsConstructor +public enum LifeCycleStatus { + CREATE(1, "已创建"), + INIT(2, "已初始化"), + RUN(3, "运行"), + DESTROY(4, "已销毁"); + + private Integer status; + private String desc; +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/BeanException.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/BeanException.java new file mode 100644 index 00000000..1f266bb4 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/BeanException.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.exception; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public class BeanException extends InternalException { + + public BeanException(String message) { + super(message); + } + + public BeanException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/InternalException.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/InternalException.java index bd4ed267..8e3b2d23 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/InternalException.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/exception/InternalException.java @@ -33,4 +33,7 @@ public class InternalException extends RuntimeException { super(message); } + public InternalException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/launcher/NeutrinoLauncher.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/launcher/NeutrinoLauncher.java index c96ea430..f5c09df9 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/launcher/NeutrinoLauncher.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/launcher/NeutrinoLauncher.java @@ -28,6 +28,7 @@ import fun.asgc.neutrino.core.constant.MetaDataConstant; import fun.asgc.neutrino.core.container.ApplicationContainer; import fun.asgc.neutrino.core.container.DefaultApplicationContainer; import fun.asgc.neutrino.core.context.ApplicationConfig; +import fun.asgc.neutrino.core.context.ApplicationContext; import fun.asgc.neutrino.core.context.Environment; import fun.asgc.neutrino.core.util.*; import lombok.extern.slf4j.Slf4j; @@ -64,9 +65,15 @@ public class NeutrinoLauncher { stopWatch.start(); environmentInit(); - this.applicationContainer = new DefaultApplicationContainer(environment); +// this.applicationContainer = new DefaultApplicationContainer(environment); +// SystemUtil.RunContext runContext = SystemUtil.waitProcessDestroy(() -> { +// this.applicationContainer.destroy(); +// log.info("Application already stop."); +// }); + ApplicationContext context = new ApplicationContext(environment); + context.run(); SystemUtil.RunContext runContext = SystemUtil.waitProcessDestroy(() -> { - this.applicationContainer.destroy(); + context.destroy(); log.info("Application already stop."); }); diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/Assert.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/Assert.java index f6c5994f..50c61468 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/Assert.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/Assert.java @@ -204,6 +204,12 @@ public abstract class Assert { } } + public static void notEmpty(String s, String message) { + if (StringUtil.isEmpty(s)) { + throw new IllegalArgumentException(message); + } + } + /** * * @param array diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/BeanManager.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/BeanManager.java index a58db5ef..4f045a3e 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/BeanManager.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/BeanManager.java @@ -25,13 +25,11 @@ package fun.asgc.neutrino.core.util; import fun.asgc.neutrino.core.container.BeanContainer; import fun.asgc.neutrino.core.context.ApplicationConfig; import fun.asgc.neutrino.core.context.ApplicationContext; -import fun.asgc.neutrino.core.context.Bean; +import fun.asgc.neutrino.core.bean.BeanWrapper; import fun.asgc.neutrino.core.context.Environment; import lombok.extern.slf4j.Slf4j; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -64,7 +62,7 @@ public class BeanManager { return context; } else { if (null != context.getBeanContainer()) { - Bean bean = context.getBeanContainer().getBean(name); + BeanWrapper bean = context.getBeanContainer().getBean(name); if (null != bean) { if (!bean.hasInstance()) { bean.newInstance(context); @@ -90,7 +88,7 @@ public class BeanManager { return (T)context; } else { if (null != context.getBeanContainer()) { - Bean bean = context.getBeanContainer().getBean(clazz); + BeanWrapper bean = context.getBeanContainer().getBean(clazz); if (null != bean) { if (!bean.hasInstance()) { bean.newInstance(context); @@ -113,7 +111,7 @@ public class BeanManager { return null; } return context.getBeanContainer().beanList().stream() - .map(Bean::getClazz) + .map(BeanWrapper::getType) .filter(item -> superClass.isAssignableFrom(item)) .map(item -> (T)getBean(item)) .filter(Objects::nonNull) diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/CollectionUtil.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/CollectionUtil.java index 02f0ea0c..6b78d142 100644 --- a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/CollectionUtil.java +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/CollectionUtil.java @@ -25,6 +25,7 @@ package fun.asgc.neutrino.core.util; import org.apache.commons.lang3.ObjectUtils; import java.util.*; +import java.util.function.Supplier; /** * @@ -60,6 +61,11 @@ public class CollectionUtil { return !isEmpty(collection); } + public static boolean notEmpty(Map map) { + return !isEmpty(map); + } + + /** * * @param source @@ -338,4 +344,21 @@ public class CollectionUtil { } return elements.toArray(array); } + + /** + * 将另一个集合的内容添加到指定集合中 + * @param supplier + * @param list + */ + public static List addAll(Supplier> supplier, List ...list) { + List res = supplier.get(); + if (ArrayUtil.notEmpty(list)) { + for (List l : list) { + if (null != l && CollectionUtil.notEmpty(l)) { + res.addAll(l); + } + } + } + return res; + } } diff --git a/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/FunctionUtil.java b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/FunctionUtil.java new file mode 100644 index 00000000..629f4df6 --- /dev/null +++ b/neutrino-core/src/main/java/fun/asgc/neutrino/core/util/FunctionUtil.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.util; + +import java.util.function.Supplier; + +/** + * 函数工具 + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public class FunctionUtil { + + /** + * 获取第一个非空值 + * @param suppliers + * @param + * @return + */ + public static T getFirstNotNull(Supplier ...suppliers) { + T res; + if (ArrayUtil.notEmpty(suppliers)) { + for (Supplier supplier : suppliers) { + if (null != supplier) { + res = supplier.get(); + if (null != res) { + return res; + } + } + } + } + return null; + } + +} diff --git a/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Dog.java b/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Dog.java index 73c29822..28baf856 100644 --- a/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Dog.java +++ b/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Dog.java @@ -39,4 +39,10 @@ public class Dog { public String say(String msg) { return "狗说:" + msg; } + + // static 测试static方法 + public int calc(int x, int y) { + System.out.println("计算 " + x + " + " + "y"); + return x + y; + } } diff --git a/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Test1.java b/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Test1.java index 87363934..532b0851 100644 --- a/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Test1.java +++ b/neutrino-core/src/test/java/fun/asgc/neutrino/core/aop/Test1.java @@ -54,4 +54,10 @@ public class Test1 { System.out.println(cat.calc(10, 6)); } + @Test + public void dogCalc() { + Dog dog = Aop.get(Dog.class); + System.out.println(dog.calc(1, 2)); + } + } diff --git a/neutrino-core/src/test/java/fun/asgc/neutrino/core/bean/BeanIdentityTest.java b/neutrino-core/src/test/java/fun/asgc/neutrino/core/bean/BeanIdentityTest.java new file mode 100644 index 00000000..978b8d78 --- /dev/null +++ b/neutrino-core/src/test/java/fun/asgc/neutrino/core/bean/BeanIdentityTest.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2022 aoshiguchen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package fun.asgc.neutrino.core.bean; + +import fun.asgc.neutrino.core.aop.Animal; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author: aoshiguchen + * @date: 2022/7/1 + */ +public class BeanIdentityTest { + + @Test + public void test1() { + System.out.println(new BeanIdentity("animal", Animal.class).equals(new BeanIdentity("animal", Animal.class))); + System.out.println(new BeanIdentity("animal", Animal.class) == new BeanIdentity("animal", Animal.class)); + } + + @Test + public void test2() { + Map map = new HashMap<>(); + map.put(new BeanIdentity("1", String.class), "1"); + map.put(new BeanIdentity("1", String.class), "2"); + System.out.println(map); + } + +}