最近在知乎看到一个GitHub项目,觉得适合自己学习,就打算深入研究,这里是GitHub的地址:https://github.com/biezhi/blade
附带作者大大自己写的说明:https://www.gitbook.com/book/biezhi/blade-in-action/details
依照作者写的教程,可以搭建一个简单的页面,现在开始探索blade源码,从开始注册路由开始解析。。。
根据作者自己的介绍:The Blade is the core operating class of the framework,which can be used to register routes,modify the template engine, set the file list display,static resource directory, and so on.可以知道Blade类是这个框架的核心类,可以注册路由、修改文件引擎、设置静态资源目录之类的操作。其类图大致如下:
先用me()方法创建一个新的Blade对象,blade对象里,有几个重要的属性:
/**
* Copyright (c) 2017, biezhi 王爵 ([email protected])
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.blade;
import com.blade.event.BeanProcessor;
import com.blade.event.EventListener;
import com.blade.event.EventManager;
import com.blade.event.EventType;
import com.blade.exception.BladeException;
import com.blade.ioc.Ioc;
import com.blade.ioc.SimpleIoc;
import com.blade.kit.Assert;
import com.blade.kit.BladeKit;
import com.blade.kit.IOKit;
import com.blade.kit.StringKit;
import com.blade.mvc.SessionManager;
import com.blade.mvc.handler.DefaultExceptionHandler;
import com.blade.mvc.handler.ExceptionHandler;
import com.blade.mvc.handler.RouteHandler;
import com.blade.mvc.handler.WebSocketHandler;
import com.blade.mvc.hook.WebHook;
import com.blade.mvc.http.HttpMethod;
import com.blade.mvc.http.HttpSession;
import com.blade.mvc.http.Session;
import com.blade.mvc.route.RouteMatcher;
import com.blade.mvc.ui.template.DefaultEngine;
import com.blade.mvc.ui.template.TemplateEngine;
import com.blade.server.Server;
import com.blade.server.netty.NettyServer;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import static com.blade.mvc.Const.*;
/**
* Blade Core
* <p>
* The Blade is the core operating class of the framework,
* which can be used to register routes,
* modify the template engine, set the file list display,
* static resource directory, and so on.
*
* @author biezhi 2017/5/31
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Blade {
/**
* Project middleware list,
* the default is empty, when you use the time you can call the use of methods to add.
* <p>
* Blade provide you with BasicAuthMiddleware, CsrfMiddleware,
* you can customize the implementation of some middleware
*/
private List<WebHook> middleware = new ArrayList<>();
/**
* BeanProcessor list, which stores all the actions that were performed before the project was started
*/
private List<BeanProcessor> processors = new ArrayList<>();
/**
* All need to be scanned by the package, when you do not set the time will scan com.blade.plugin package
*/
private Set<String> packages = new LinkedHashSet<>(PLUGIN_PACKAGE_NAME);
/**
* All static resource URL prefixes,
* defaults to "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/",
* which are located under classpath
*/
private Set<String> statics = new HashSet<>(DEFAULT_STATICS);
/**
* The default IOC container implementation
*/
private Ioc ioc = new SimpleIoc();
/**
* The default template engine implementation, this is a very simple, generally not put into production
*/
private TemplateEngine templateEngine = new DefaultEngine();
/**
* Event manager, which manages all the guys that will trigger events
*/
private EventManager eventManager = new EventManager();
/**
* Session manager, which manages session when you enable session
*/
private SessionManager sessionManager = new SessionManager();
/**
* Used to wait for the start to complete the lock
*/
private CountDownLatch latch = new CountDownLatch(1);
/**
* Web server implementation, currently only netty
*/
private Server server = new NettyServer();
/**
* A route matcher that matches whether a route exists
*/
private RouteMatcher routeMatcher = new RouteMatcher();
/**
* Blade environment, which stores the parameters of the app.properties configuration file
*/
private Environment environment = Environment.empty();
/**
* Exception handling, it will output some logs when the error is initiated
*/
private Consumer<Exception> startupExceptionHandler = (e) -> log.error("Start blade failed", e);
/**
* Exception handler, default is DefaultExceptionHandler.
* <p>
* When you need to customize the handling of exceptions can be inherited from DefaultExceptionHandler
*/
private ExceptionHandler exceptionHandler = new DefaultExceptionHandler();
/**
* Used to identify whether the web server has started
*/
private boolean started = false;
/**
* Project main class, the main category is located in the root directory of the basic package,
* all the features will be in the sub-package below
*/
private Class<?> bootClass = null;
/**
* Session implementation type, the default is HttpSession.
* <p>
* When you need to be able to achieve similar RedisSession
*/
private Class<? extends Session> sessionImplType = HttpSession.class;
/**
* WebSocket path
*/
private String webSocketPath;
/**
* Blade app start banner, default is Const.BANNER
*/
private String bannerText;
/**
* Blade app start thread name, default is Const.DEFAULT_THREAD_NAME
*/
private String threadName;
/**
* WebSocket Handler
*/
private WebSocketHandler webSocketHandler;
/**
* Give your blade instance, from then on will get the energy
*
* @return return blade instance
*/
public static Blade me() {
return new Blade();
}
/**
* Get blade ioc container, default is SimpleIoc implement.
* <p>
* IOC container will help you hosting Bean or component, it is actually a Map inside.
* In the blade in a single way to make objects reuse,
* you can save resources, to avoid the terrible memory leak
*
* @return return ioc container
*/
public Ioc ioc() {
return ioc;
}
/**
* Add a get route to routes
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade get(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.GET);
return this;
}
/**
* Add a post route to routes
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade post(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.POST);
return this;
}
/**
* Add a put route to routes
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade put(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.PUT);
return this;
}
/**
* Add a delete route to routes
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade delete(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.DELETE);
return this;
}
/**
* Add a before route to routes, the before route will be executed before matching route
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade before(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.BEFORE);
return this;
}
/**
* Add a after route to routes, the before route will be executed after matching route
*
* @param path your route path
* @param handler route implement
* @return return blade instance
*/
public Blade after(@NonNull String path, @NonNull RouteHandler handler) {
routeMatcher.addRoute(path, handler, HttpMethod.AFTER);
return this;
}
/**
* Setting blade mvc default templateEngine
*
* @param templateEngine TemplateEngine object
* @return blade
*/
public Blade templateEngine(@NonNull TemplateEngine templateEngine) {
this.templateEngine = templateEngine;
return this;
}
/**
* Get TemplateEngine, default is DefaultEngine
*
* @return return TemplateEngine
*/
public TemplateEngine templateEngine() {
return templateEngine;
}
/**
* Get RouteMatcher
*
* @return return RouteMatcher
*/
public RouteMatcher routeMatcher() {
return routeMatcher;
}
/**
* Register bean to ioc container
*
* @param bean bean object
* @return blade
*/
public Blade register(@NonNull Object bean) {
ioc.addBean(bean);
return this;
}
/**
* Register bean to ioc container
*
* @param cls bean class, the class must provide a no args constructor
* @return blade
*/
public Blade register(@NonNull Class<?> cls) {
ioc.addBean(cls);
return this;
}
/**
* Add multiple static resource file
* the default provides the static, upload
*
* @param folders static resource directory
* @return blade
*/
public Blade addStatics(@NonNull String... folders) {
statics.addAll(Arrays.asList(folders));
return this;
}
/**
* Set whether to show the file directory, default doesn't show
*
* @param fileList show the file directory
* @return blade
*/
public Blade showFileList(boolean fileList) {
this.environment(ENV_KEY_STATIC_LIST, fileList);
return this;
}
/**
* Set whether open gzip, default disabled
*
* @param gzipEnable enabled gzip
* @return blade
*/
public Blade gzip(boolean gzipEnable) {
this.environment(ENV_KEY_GZIP_ENABLE, gzipEnable);
return this;
}
/**
* Get ioc bean
*
* @param cls bean class type
* @return return bean instance
*/
public Object getBean(@NonNull Class<?> cls) {
return ioc.getBean(cls);
}
/**
* Get ExceptionHandler
*
* @return return ExceptionHandler
*/
public ExceptionHandler exceptionHandler() {
return exceptionHandler;
}
/**
* Set ExceptionHandler, when you need a custom exception handling
*
* @param exceptionHandler your ExceptionHandler instance
* @return return blade instance
*/
public Blade exceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
return this;
}
/**
* Get current is developer mode
*
* @return return true is developer mode, else not.
*/
public boolean devMode() {
return environment.getBoolean(ENV_KEY_DEV_MODE, true);
}
/**
* Whether encoding setting mode for developers
* The default mode is developers
*
* @param devMode developer mode
* @return blade
*/
public Blade devMode(boolean devMode) {
this.environment(ENV_KEY_DEV_MODE, devMode);
return this;
}
public Class<?> bootClass() {
return this.bootClass;
}
/**
* Set whether to enable cors
*
* @param enableCors enable cors
* @return blade
*/
public Blade enableCors(boolean enableCors) {
this.environment(ENV_KEY_CORS_ENABLE, enableCors);
return this;
}
/**
* Get blade statics list.
* e.g: "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/"
*
* @return return statics
*/
public Set<String> getStatics() {
return statics;
}
/**
* When set to start blade scan packages
*
* @param packages package name
* @return blade
*/
public Blade scanPackages(@NonNull String... packages) {
this.packages.addAll(Arrays.asList(packages));
return this;
}
/**
* Get scan the package set.
*
* @return return packages set
*/
public Set<String> scanPackages() {
return packages;
}
/**
* Set to start blade configuration file by default
* Boot config properties file in classpath directory.
* <p>
* Without setting will read the classpath -> app.properties
*
* @param bootConf boot config file name
* @return blade
*/
public Blade bootConf(@NonNull String bootConf) {
this.environment(ENV_KEY_BOOT_CONF, bootConf);
return this;
}
/**
* Set the environment variable for global use here
*
* @param key environment key
* @param value environment value
* @return blade
*/
public Blade environment(@NonNull String key, @NonNull Object value) {
environment.set(key, value);
return this;
}
public Environment environment() {
return environment;
}
/**
* Set to start the web server to monitor port, the default is 9000
*
* @param port web server port
* @return blade
*/
public Blade listen(int port) {
Assert.greaterThan(port, 0, "server port not is negative number.");
this.environment(ENV_KEY_SERVER_PORT, port);
return this;
}
/**
* Set to start the web server to listen the IP address and port
* The default will listen 0.0.0.0:9000
*
* @param address ip address
* @param port web server port
* @return blade
*/
public Blade listen(@NonNull String address, int port) {
Assert.greaterThan(port, 0, "server port not is negative number.");
this.environment(ENV_KEY_SERVER_ADDRESS, address);
this.environment(ENV_KEY_SERVER_PORT, port);
return this;
}
/**
* The use of multiple middleware, if any
*
* @param middleware middleware object array
* @return blade
*/
public Blade use(@NonNull WebHook... middleware) {
if (!BladeKit.isEmpty(middleware)) {
this.middleware.addAll(Arrays.asList(middleware));
}
return this;
}
/**
* Get middleware list
*
* @return return middleware list
*/
public List<WebHook> middleware() {
return this.middleware;
}
/**
* Set in the name of the app blade application
*
* @param appName application name
* @return blade
*/
public Blade appName(@NonNull String appName) {
this.environment(ENV_KEY_APP_NAME, appName);
return this;
}
/**
* Add a event listener
* When the trigger event is executed eventListener
*
* @param eventType event type
* @param eventListener event listener
* @return blade
*/
public Blade event(@NonNull EventType eventType, @NonNull EventListener eventListener) {
eventManager.addEventListener(eventType, eventListener);
return this;
}
/**
* Get session implements Class Type
*
* @return return blade Session Type
*/
public Class<? extends Session> sessionType() {
return this.sessionImplType;
}
/**
* Set session implements Class Type, e.g: RedisSession
*
* @param sessionImplType Session Type implement
* @return return blade instance
*/
public Blade sessionType(Class<? extends Session> sessionImplType) {
this.sessionImplType = sessionImplType;
return this;
}
/**
* Event on started
*
* @param processor bean processor
* @return return blade instance
*/
public Blade onStarted(@NonNull BeanProcessor processor) {
processors.add(processor);
return this;
}
/**
* Get processors
*
* @return return processors
*/
public List<BeanProcessor> processors() {
return processors;
}
/**
* Get EventManager
*
* @return return EventManager
*/
public EventManager eventManager() {
return eventManager;
}
/**
* Get SessionManager
*
* @return return SessionManager
*/
public SessionManager sessionManager() {
return sessionManager;
}
/**
* Disable session, default is open
*
* @return return blade instance
*/
public Blade disableSession() {
this.sessionManager = null;
return this;
}
/**
* Start blade application.
* <p>
* When all the routing in the main function of situations you can use,
* Otherwise please do not call this method.
*
* @return return blade instance
*/
public Blade start() {
return this.start(null, null);
}
/**
* Start blade application
*
* @param mainCls main Class, the main class bag is basic package
* @param args command arguments
* @return return blade instance
*/
public Blade start(Class<?> mainCls, String... args) {
return this.start(mainCls, DEFAULT_SERVER_ADDRESS, DEFAULT_SERVER_PORT, args);
}
/**
* Start the blade web server
*
* @param bootClass Start the boot class, used to scan the class in all of the packages
* @param address web server bind ip address
* @param port web server bind port
* @param args launch parameters
* @return blade
*/
public Blade start(Class<?> bootClass, @NonNull String address, int port, String... args) {
try {
environment.set(ENV_KEY_SERVER_ADDRESS, address);
Assert.greaterThan(port, 0, "server port not is negative number.");
this.bootClass = bootClass;
eventManager.fireEvent(EventType.SERVER_STARTING, this);
Thread thread = new Thread(() -> {
try {
server.start(Blade.this, args);
latch.countDown();
server.join();
} catch (Exception e) {
startupExceptionHandler.accept(e);
}
});
String threadName = null != this.threadName ? this.threadName : environment.get(ENV_KEY_APP_THREAD_NAME, null);
threadName = null != threadName ? threadName : DEFAULT_THREAD_NAME;
thread.setName(threadName);
thread.start();
started = true;
} catch (Exception e) {
startupExceptionHandler.accept(e);
}
return this;
}
/**
* Await web server started
*
* @return return blade instance
*/
public Blade await() {
if (!started) {
throw new IllegalStateException("Server hasn't been started. Call start() before calling this method.");
}
try {
latch.await();
} catch (Exception e) {
log.error("await error", e);
Thread.currentThread().interrupt();
}
return this;
}
/**
* Stop current blade application
* <p>
* Will stop synchronization waiting netty service
*/
public void stop() {
eventManager.fireEvent(EventType.SERVER_STOPPING, this);
server.stopAndWait();
eventManager.fireEvent(EventType.SERVER_STOPPED, this);
}
/**
* Register WebSocket path
*
* @param path websocket path
* @param handler websocket handler
* @return return blade instance
*/
public Blade webSocket(@NonNull String path, @NonNull WebSocketHandler handler) {
if (null != this.webSocketHandler) {
throw new BladeException(500, "There is already a WebSocket path.");
}
this.webSocketPath = path;
this.webSocketHandler = handler;
System.out.println(String.format("\n\t\t\t\t\t\t\t\t\t\t\t\t\t" +
"\t\t\t\t\t Register WebSocket Path: %s\n", path));
return this;
}
/**
* Get webSocket path
*
* @return return websocket path
*/
public String webSocketPath() {
return webSocketPath;
}
/**
* Set blade start banner text
*
* @param bannerText banner text
* @return return blade instance
*/
public Blade bannerText(String bannerText) {
this.bannerText = bannerText;
return this;
}
/**
* Get banner text
*
* @return return blade start banner text
*/
public String bannerText() {
if (null != bannerText) return bannerText;
String bannerPath = environment.get(ENV_KEY_BANNER_PATH, null);
if (StringKit.isNotBlank(bannerPath) && Files.exists(Paths.get(bannerPath))) {
try {
bannerText = IOKit.readToString(bannerPath);
} catch (Exception e) {
}
return bannerText;
}
return null;
}
/**
* Set blade start thread name
*
* @param threadName thread name
* @return return blade instance
*/
public Blade threadName(String threadName) {
this.threadName = threadName;
return this;
}
/**
* Get WebSocket Handler
*
* @return return websocket handler
*/
public WebSocketHandler webSocketHandler() {
return webSocketHandler;
}
}
先分析Blade中构建Ioc容器的过程。在代码第99行中,有一句 private Ioc ioc = new SimpleIoc();
Blade里实现一个默认的ioc容器,将一些默认的对象存储到ioc容器中,再新建一个SimpleIoc对象,其类图如下:
SimpleIoc类
package com.blade.ioc;
import com.blade.ioc.bean.BeanDefine;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* The default IOC container implementation
*
* @author <a href="mailto:[email protected]" target="_blank">biezhi</a>
* @since 1.5
*/
@Slf4j
public class SimpleIoc implements Ioc {
private final Map<String, BeanDefine> pool = new HashMap<>(32);
/**
* Add user-defined objects
*/
@Override
public void addBean(Object bean) {
addBean(bean.getClass().getName(), bean);
}
/**
* Add user-defined objects
*/
@Override
public void addBean(String name, Object bean) {
BeanDefine beanDefine = new BeanDefine(bean);
addBean(name, beanDefine);
// add interface
Class<?>[] interfaces = beanDefine.getType().getInterfaces();
if (interfaces.length > 0) {
for (Class<?> interfaceClazz : interfaces) {
this.addBean(interfaceClazz.getName(), beanDefine);
}
}
}
/**
* Update BeanDefine
*/
@Override
public void setBean(Class<?> type, Object proxyBean) {
BeanDefine beanDefine = pool.get(type.getName());
if (beanDefine != null) {
beanDefine.setBean(proxyBean);
} else {
beanDefine = new BeanDefine(proxyBean, type);
}
pool.put(type.getName(), beanDefine);
}
/**
* Register @Bean marked objects
*/
@Override
public <T> T addBean(Class<T> type) {
Object bean = addBean(type, true);
return type.cast(bean);
}
@Override
public <T> T getBean(Class<T> type) {
Object bean = this.getBean(type.getName());
try {
return type.cast(bean);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public Object getBean(String name) {
BeanDefine beanDefine = pool.get(name);
if (beanDefine == null) {
return null;
}
return beanDefine.getBean();
}
@Override
public List<BeanDefine> getBeanDefines() {
return new ArrayList<>(pool.values());
}
@Override
public BeanDefine getBeanDefine(Class<?> type) {
return this.getBeanDefine(type, true);
}
@Override
public List<Object> getBeans() {
Set<String> beanNames = this.getBeanNames();
List<Object> beans = new ArrayList<>(beanNames.size());
for (String beanName : beanNames) {
Object bean = this.getBean(beanName);
if (null != bean) {
beans.add(bean);
}
}
return beans;
}
@Override
public Set<String> getBeanNames() {
return pool.keySet();
}
@Override
public void remove(String beanName) {
pool.remove(beanName);
}
@Override
public void remove(Class<?> type) {
pool.remove(type.getSimpleName());
}
@Override
public void clearAll() {
pool.clear();
}
/**
* Add user-defined objects
*/
private void addBean(String name, BeanDefine beanDefine) {
if (pool.put(name, beanDefine) != null) {
log.warn("Duplicated Bean: {}", name);
}
}
/**
* Register @Bean marked objects
*/
private Object addBean(Class<?> type, boolean singleton) {
return addBean(type.getName(), type, singleton);
}
/**
* Register @Bean marked objects
*/
private Object addBean(String name, Class<?> beanClass, boolean singleton) {
BeanDefine beanDefine = this.getBeanDefine(beanClass, singleton);
if (pool.put(name, beanDefine) != null) {
log.warn("Duplicated Bean: {}", name);
}
// add interface
Class<?>[] interfaces = beanClass.getInterfaces();
if (interfaces.length > 0) {
for (Class<?> interfaceClazz : interfaces) {
if (null != this.getBean(interfaceClazz)) {
break;
}
this.addBean(interfaceClazz.getName(), beanDefine);
}
}
return beanDefine.getBean();
}
private BeanDefine getBeanDefine(Class<?> beanClass, boolean singleton) {
try {
Object object = beanClass.newInstance();
return new BeanDefine(object, beanClass, singleton);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
其中BeanDefine类定义了一个ioc的目标
package com.blade.ioc.bean;
/**
* Bean Define, IOC to define a target
*
* @author <a href="mailto:[email protected]" target="_blank">biezhi</a>
* @since 1.5
*/
public class BeanDefine {
private Object bean;
private Class<?> type;
private boolean isSingle;
public BeanDefine(Object bean) {
this(bean, bean.getClass());
}
public BeanDefine(Object bean, Class<?> type) {
this.bean = bean;
this.type = type;
this.isSingle = true;
}
public BeanDefine(Object bean, Class<?> type, boolean isSingle) {
this.bean = bean;
this.type = type;
this.isSingle = isSingle;
}
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public boolean isSingle() {
return isSingle;
}
public void setSignle(boolean isSingle) {
this.isSingle = isSingle;
}
}
又因为SimpleIoc类中,私有属性:
private final Map<String, BeanDefine> pool = new HashMap<>(32);
所以在启动的时候,SimpleIoc对象会先创建一个ioc的池子pool,用来实现ioc的存储Bean对象。每个pool里的对象,有三个属性:bean的名称、class类型的type、还是一个布尔值。
接下来再回到Blade中看代码,框架中先注册一个Object对象到ioc容器中,调用SimpleIoc中的addBean(Object bean)方法:
public void addBean(Object bean) {
addBean(bean.getClass().getName(), bean);
}
再调用addBean(String name, Object bean)方法:
public void addBean(String name, Object bean) {
BeanDefine beanDefine = new BeanDefine(bean);
addBean(name, beanDefine);
// add interface
Class<?>[] interfaces = beanDefine.getType().getInterfaces();
if (interfaces.length > 0) {
for (Class<?> interfaceClazz : interfaces) {
this.addBean(interfaceClazz.getName(), beanDefine);
}
}
}
先创建一个BeanDefine对象,然后调用addBean(String name, BeanDefine beanDefine)方法,向一开始定义的IOC容器pool池子中添加用户定义的对象。
再通过for循环获得这个对象所有接口,然后把这些再次用addBean(String name, BeanDefine beanDefine)方法添加进去。
那么这个方法就完成了,继续
接下来又注册一个任意类型的class,调用addBean(Class<T> type)方法:
public <T> T addBean(Class<T> type) {
Object bean = addBean(type, true);
return type.cast(bean);
}
返回通过此Class对象所表示的类或接口
,
调用addBean(Class<?> type, boolean singleton)方法:
private Object addBean(Class<?> type, boolean singleton) {
return addBean(type.getName(), type, singleton);
}
再通过addBean(String name, Class<?> beanClass, boolean singleton)方法:
private Object addBean(String name, Class<?> beanClass, boolean singleton) {
BeanDefine beanDefine = this.getBeanDefine(beanClass, singleton);
if (pool.put(name, beanDefine) != null) {
log.warn("Duplicated Bean: {}", name);
}
// add interface
Class<?>[] interfaces = beanClass.getInterfaces();
if (interfaces.length > 0) {
for (Class<?> interfaceClazz : interfaces) {
if (null != this.getBean(interfaceClazz)) {
break;
}
this.addBean(interfaceClazz.getName(), beanDefine);
}
}
return beanDefine.getBean();
}
此方法中先调用getBeanDefine(Class<?> beanClass, boolean singleton)方法:
private BeanDefine getBeanDefine(Class<?> beanClass, boolean singleton) {
try {
Object object = beanClass.newInstance();
return new BeanDefine(object, beanClass, singleton);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
先将一开始从Blade传递过来的Class<?>对象,创建此Class对象所表示的类的新实例
。再返回一个BeanDefine对象,
再在addBean()方法中,先检验pool中有没有这个bean,然后获取Blade传递过来的Class<?>所有的实例,然后把这些再次用addBean(String name, BeanDefine beanDefine)方法添加进IOC容器的pool池子中去。
这样这个IOC容器就可以完成存储对象的功能,其他的下次再进行分析了。。。
不过从代码中看出作者使用Java反射机制完成设计ioc,改天去研究jvm的反射机制吧。。。