DIã³ã³ãã使ã£ã¦ããã©ãã¢ããã¼ã·ã§ã³ã£ã¦ãªããªã®ï¼ã£ã¦èããã¦ãä½ã£ã¦ã¿ããããããã¨çãã¦ã¿ãã®ã§ãèªåã§ãä½ã£ã¦ã¿ã¾ããã
ããããã£ãã
ãDIã³ã³ãã使ãã¨ä½ãããã®ï¼ãã¨ãããã¨ããä½ã£ã¦ã¿ãã¨ãããã¾ãããã¨ãDIã£ã¦ä½ãããã®ï¼ãã«é¢ãã¦ã¯ããDIã¯ã¡ãã£ã¨ã³ã¼ããæ¸ãã®ã楽ã«ãªãã ãã§ãããã ããã£ã¦ãä»æ¹ãªãã大äºãªã®ã¯ã³ã³ãããã¨çããããã«ãã¦ã¾ãããã³ã¼ãæ¯çãããããããããããã¾ãã
ç¶ç·¨ã¨ãã¦Webãã¬ã¼ã ã¯ã¼ã¯ãä½ã£ã¦ããã®ã§åèã¾ã§ã
作って理解するWebフレームワーク - きしだのHatena
ã¾ãã¯ã³ã³ãããä½ã
ã¨ãããã1ã½ã¼ã¹ã®ç¶æ
ã§ã
ãããªæãã§ã管çããåãç»é²ã§ããããã«ãã¾ãã
static Map<String, Class> types = new HashMap<>(); static void register(String name, Class type) { types.put(name, type); }
ããã§ãååãæå®ãã¦ãªãã¸ã§ã¯ããåãåºããããã«ãããã¨ã
static Map<String, Object> beans = new HashMap<>(); static Object getBean(String name) { return beans.computeIfAbsent(name, key -> { Class type = types.get(name); Objects.requireNonNull(type, name + " not found."); return type.newInstance(); }); }
ãã¨ã¯ã¯ã©ã¹ãç»é²ãã¦ã
Context.register("foo", Foo.class); Context.register("bar", Bar.class);
ãªãã¸ã§ã¯ããåãåºãã
Bar bar = (Bar) Context.getBean("bar");
ãã®æç¹ã§ã¯åãªããªãã¸ã§ã¯ããã¼ã«ã§ããã
tinydi/Main.java at da602927261402d9c9c1a197ccd12c41c5fcbb33 · kishida/tinydi
DIãã¦ã¿ã
ãã¦ãgetBeanã¨ããã¡ãã¡ããã®ã¯é¢åãªã®ã§ãé¢é£ãããªãã¸ã§ã¯ãã¯åæã«ç¨æãã¦ããããã«ãã¾ãããã
ããã§ã¯ãæ¨æºã¢ããã¼ã·ã§ã³ã®@Injectã使ãã¾ãã
ãªãã¸ã§ã¯ããç¨æããã¨ãã«ããªãã¬ã¯ã·ã§ã³ã§ãã£ã¼ã«ããã¨ã£ã¦ãã¦ã@Injectã¢ããã¼ã·ã§ã³ãã¤ãã¦ãããã£ã¼ã«ãåã§ãªãã¸ã§ã¯ããåå¾ãããã¨ã
private static <T> T createObject(Class<T> type) { T object = type.newInstance(); for (Field field : type.getDeclaredFields()) { if (!field.isAnnotationPresent(Inject.class)) { continue; } field.setAccessible(true); field.set(object, getBean(field.getName())); } return object; }
ããã§ãããªæãã®ã¤ã³ã¸ã§ã¯ã·ã§ã³ãã§ããããã«ãªãã¾ãã
@Inject
Foo foo;
èªåç»é²ãã
registerã¨ãããã®ãé¢åãªã®ã§ãã¢ããã¼ã·ã§ã³ãã¤ããã¯ã©ã¹ãèªåã§ç»é²ã§ããããã«ãã¾ãã
public static void autoRegister() { URL res = Context.class.getResource( "/" + Context.class.getName().replace('.', '/') + ".class"); Path classPath = new File(res.toURI()).toPath().resolve("../../.."); Files.walk(classPath) .filter(p -> !Files.isDirectory(p)) .filter(p -> p.toString().endsWith(".class")) .map(p -> classPath.relativize(p)) .map(p -> p.toString().replace(File.separatorChar, '.')) .map(n -> n.substring(0, n.length() - 6)) .forEach(n -> { Class c = Class.forName(n); if (c.isAnnotationPresent(Named.class)) { String simpleName = c.getSimpleName(); register(simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1), c); } }); } }
ã¾ãèªåã®ã¯ã©ã¹ã®ã¯ã©ã¹ãã¡ã¤ã«ããªã½ã¼ã¹ã¨ãã¦ã¨ã£ã¦ãã¦ãããããã¯ã©ã¹ãã¹ã®ãã©ã«ããåå¾ãã¦ããã®ä¸ã®.classã¨ããæ¡å¼µåã®ãã¡ã¤ã«ãå
¨é¨ã¨ã£ã¦ãã¦ãããããã¯ã©ã¹åãä½ã£ã¦èªã¿è¾¼ãã§ã¿ã¦ã@Namedãã¤ãã¦ãã°ç»é²ãããã¨ããªãã¨ããç´ æµãªå¦çã
ããã§ã@Namedãã¤ããã¯ã©ã¹ãèªåçã«ç»é²ããã¾ãã
ã¾ããããã§DIã¨ãããã®ãã§ããããã«ãªã£ãã®ã§ããããããå
¨ç¶ç´ æµã§ã¯ãªãã§ãããã
ãã以éãã©ãã ãæ©è½æ¡å¼µãã¦ãã£ã¦ããDIã¨ããæ©è½ã¯ã³ã³ã¹ãã©ã¯ã¿ã¤ã³ã¸ã§ã¯ã·ã§ã³ã¨ãããªã¨ã¼ã·ã§ã³ãå¢ããã ãã§ã»ã¨ãã©å¤ãããªãã§ããã¤ã¾ããDIã ãã§ãã¦ãä½ããããããªãã¨ãããã¨ã§ãã
Auto register! · kishida/tinydi@4449c53
AOPãã¦ã¿ã
ã¡ãã£ã¨å¬ãããåºãããã«AOPãã¦ã¿ã¾ããããã¨ã¯ããæ±ç¨ã®AOPãã¬ã¼ã ã¯ã¼ã¯ã«ããã®ã¯å¤§å¤ãªã®ã§ãããã§ã¯ã¢ããã¼ã·ã§ã³ãã¤ããã¡ã½ãããå¼ã³åºãããã¨ãã«æå»ã¨ã¡ã½ããåãåºåãããã¨ãããã¨ããã£ã¦ã¿ã¾ãã
ãããã©ããã£ã¦å®è£ ãããããªã®ã§ãããç»é²ããã¯ã©ã¹ãç¶æ¿ããã¯ã©ã¹ãä½ã£ã¦ããã°ãåºãã¡ã½ããããªã¼ãã¼ã©ã¤ããã¦ãã°åºåå¦çãã¯ãããã¨ããæ¹éã§ãã
class Foo{ @InvokeLog void hoge(){ some(); } }
ã¨ããã¯ã©ã¹ãç»é²ãããã¨ãã«
class Foo$$ extends Foo{ void hoge() { log(); super.hoge(); } }
ã¨ããã¯ã©ã¹ã®ãªãã¸ã§ã¯ããä½ã£ã¦è¿ãããã«ããããã§ãã
ããã§è£å´ã§ã¯ã©ã¹ãä½ããªãã¨ããã¾ããã
æ¨æºã®Javaã§ã¯ãProxyã¨ããä»çµã¿ããã£ã¦æ±ããåä½ãå®ç¾å¯è½ã§ãããã¤ã³ã¿ãã§ã¼ã¹ã¨ãã¦ç»é²ããå¿
è¦ãããã¾ãã
å¤ãDIã³ã³ãããã¤ã³ã¿ãã§ã¼ã¹ãå¿
è¦ã¨ãã¦ããã®ã¯ããããã£ãå®è£
ä¸ã®å¶ç´ã«ãããã®ã§ããããã¦å®è£
ä¸ã®å¶ç´ã«ããããããããããªã®ããã©ãã¨ãã声ã«å¯¾ãã¦ãã¤ã³ã¿ãã§ã¼ã¹ã«å¯¾ãã¦å®è£
ãè¡ãã®ã ï¼ãã¿ããã«è¨è¨æ¹éããããã¦æ£å½åãã¦ããããã§ããã
ãããã¼ããã¡ã¯ããç®ãè¦ãã¦ãã¾ã£ã¦ããã®ã§ããããããããã¨ã«ã¯ã ã¾ããã¾ãããã
ã¨ã¯ããããããã©ããã£ã¦å®ç¾ãããã§ããããã¤ãã³ã¼ãæä½ã¨ããéã®æè¡ãéçºããã¦ãå®è¡æã«ãã¤ãã³ã¼ããçæãããã¨ãã§ããcglibãjavassistã¨ãã£ãã©ã¤ãã©ãªãåºã¦ãã¾ããããã®ãã¤ãã³ã¼ãæä½æè¡ããä»ã®Javaã®ãEase of Developmentããæ¯ãã¦ããã¨ãã£ã¦ãéè¨ã§ã¯ãªãã¨æãã¾ãã
ããã§ã¯Javassistã使ãã¾ãã
ã¯ã©ã¹åã«ã$$ããã¤ããæ°ããªã¯ã©ã¹ãä½ã£ã¦ãå
ã®ã¯ã©ã¹ãç¶æ¿ããã¾ãã
CtClass cls = pool.makeClass(type.getName() + "$$");
cls.setSuperclass(orgCls);
ã§ãprintlnãã¤ã¤ãªã¼ãã¼ã©ã¤ãå
ãå¼ã³åºãã¡ã½ãããä½ã£ã¦è¿½å ããããã§ãã
newMethod.setBody( "{" + " System.out.println(java.time.LocalDateTime.now() + " + "\":" + method.getName() + " invoked.\"); " + " return super." + method.getName() + "($$);" + "}"); cls.addMethod(newMethod);
ãã®ããã«ããã¬ã¼ã ã¯ã¼ã¯å
ã§ãªãã¬ã¯ã·ã§ã³ããã¤ãã³ã¼ãæä½ãè¡ã£ã¦Javaã®æ¨æºçãªä»çµã¿ã§ã¯ã§ããªããã¨ãå®ç¾ãããã¨ã§ãè¨èªä»æ§ã®å¶ç´ãã¯ãããå¦çããã¢ããªã±ã¼ã·ã§ã³ã¨ãã¦ã¯è¨èªä»æ§å
ã§æ¸ããããã«ãããã¨ããã®ãã¢ããã¼ã·ã§ã³ãDIã³ã³ããã®å©ç¨ä¾¡å¤ã ã¨æãã¾ãã
AOP! · kishida/tinydi@18f200d
ã¹ã³ã¼ããå®ç¾©ãã
æå¾ã«ãã¹ã³ã¼ããå®è£
ãã¦ã¿ã¾ãã
ã¹ã³ã¼ãã¨ãã¦ã¯ãã¢ããªã±ã¼ã·ã§ã³ã¹ã³ã¼ãã¨ãªã¯ã¨ã¹ãã¹ã³ã¼ããå®è£
ã§ããã°ãä¸éçãªã¹ã³ã¼ãã¯å¿ç¨å¯è½ãªã®ã§ãä»åã¯ãã®2ã¤ã®ã¹ã³ã¼ããå®è£
ãã¾ãã
ã¨ãããããä½ã«ãã¤ãã¦ãªããã°ã¢ããªã±ã¼ã·ã§ã³ã¹ã³ã¼ãã¨ãããã¨ã«ãã¾ããã¾ããä»åã¯ç¹ã«Webã¢ããªã±ã¼ã·ã§ã³ãä½ã£ã¦ãããã§ããªãã®ã§ãã¹ã¬ãããã¨ã®ã¹ã³ã¼ãããªã¯ã¨ã¹ãã¹ã³ã¼ãã¨ãããã¨ã«ãã¦ããã¾ãã
ãªãã¸ã§ã¯ãã®ä¿æã«é¢ãã¦ã¯ãThreadLocalã§ãªãã¸ã§ã¯ãæ ¼ç´å ´æãç¨æããã°ããã§ãã
static ThreadLocal<Map<String, Object>> requestBeans = new InheritableThreadLocal<>();
ãã¨ã¯ãRequestScopedãã¤ãã¦ããã°ãã¡ãã«ãªãã¸ã§ã¯ããç»é²ããããã«ããã°å¤§ä¸å¤«ã
if (type.isAnnotationPresent(RequestScoped.class)) { scope = requestBeans.get(); if (scope == null) { scope = new HashMap<>(); requestBeans.set(scope); } }
ã¨ãåã«ãªãã¸ã§ã¯ããã¹ã³ã¼ãåä½ã§ä¿æããã ããªãããã ãã§ããã®ã§ãããDIãèããã¨ããã§ã¯åé¡ãããã¾ãã
ä¾ãã°ããããªæãã§ãRequestScopedãªã¯ã©ã¹ãç»é²ãã¾ããé常ãªãLombok使ãã¨ããã§ãããããã§ã¯ããããããã®ããã«setter/getterãã¡ããã¨æ¸ãã¦ã¾ãã
@Named @RequestScoped public class Now { private LocalDateTime time; public LocalDateTime getTime() { return time; } public void setTime(LocalDateTime time) { this.time = time; } }
ããã¦ãã¢ããªã±ã¼ã·ã§ã³ã¹ã³ã¼ãã®ã¯ã©ã¹ã«ã¤ã³ã¸ã§ã¯ããã¾ãã
@Named public class Bar { @Inject Now now; void longProcess() { now.setTime(LocalDateTime.now()); System.out.println("start:" + now.getTime()); try { Thread.sleep(5000); } catch (InterruptedException ex) { } System.out.println("end :" + now.getTime()); } }
2ç§ç½®ãã¦å¥ã¹ã¬ããã§longProcessã¡ã½ãããå¼ã³åºãã¦ã¿ã¾ãã
public static void main(String[] args) { Context.autoRegister(); Bar bar = (Bar) Context.getBean("bar"); ExecutorService es = Executors.newFixedThreadPool(2); for (int i = 0; i < 2; ++i) { es.execute(() -> { bar.longProcess(); }); Thread.sleep(2000); } es.shutdown(); }
ãããåç´ã«å®è£
ãã¦ããç¶æ
ã ã¨ãä¸åº¦nowãã£ã¼ã«ãã«å¤ãè¨å®ããã¨ãã®å¾ã¯å¤ãæ´æ°ãããªãã®ã§ãæåã®nowãªãã¸ã§ã¯ãã使ãç¶ãããã¦ãã¾ãã¾ããããã§ã¯ãã¨2ã¹ã¬ããç®ã§å¤ãæ´æ°ããã¨ãnowãã£ã¼ã«ãã¯ThreadLocalãªã©ã§ã¯ãªãæ®éã®ãã£ã¼ã«ããªã®ã§ãæåã®ã¹ã¬ããã§è¦ãnowãã£ã¼ã«ããç½®ãæãã£ã¦ãã¾ãã¾ãã
ãã¦ãã©ããã¾ãããï¼
ã¨ãããã¨ã§ãããã§ã¯è£å´ã§ãããªæãã®ã¯ã©ã¹ãä½ã£ã¦ThreadLocalã«ä¿æãããªãã¸ã§ã¯ãã«å§è²ããã°ããããã
class Now$$_ extends Now{ ThreadLocal<Now> obj; Now getObj(){ if (obj.get() == null) { obj.set(Context.getBean("now")); } return obj.get(); } public LocalDateTime getTime() { return getObj().getTime(); } public void setTime(LocalDateTime time) { getObj().setTime(time); } }
ããã§ã¾ããªãã¸ã§ã¯ãä¿æç¨ã®ã¯ã©ã¹ãä½ãã¾ã
public class LocalCache<T> { private ThreadLocal<T> local = new InheritableThreadLocal<>(); private String name; public LocalCache(String name) { this.name = name; } public T get() { T obj = local.get(); if (obj == null) { obj = (T) Context.getBean(name); local.set(obj); } return obj; } }
ãã¨ã¯å¯¿å½ã®é·ããªãã¸ã§ã¯ããã¤ã³ã¸ã§ã¯ããããã¨ãã«$$_ãã¤ããã¯ã©ã¹ãä½ã£ã¦
cls = pool.makeClass(type.getName() + "$$_");
cls.setSuperclass(orgCls);
ãã¼ã«ã«ãªãã¸ã§ã¯ããä¿æãããã£ã¼ã«ããç¨æãã¦
CtClass tl = pool.get(LocalCache.class.getName()); CtField org = new CtField(tl, "org", cls); cls.addField(org, "new " + LocalCache.class.getName() + "(\"" + name + "\");");
åã¡ã½ããã«å¯¾å¿ããå§è²ã¡ã½ãããä½ãã°ãã£ãã¼ã
override.setBody( "{" + " return ((" + type.getName() + ")org.get())." + method.getName() + "($$);" + "}"); cls.addMethod(override);
ãããããã¨ã§ã寿å½ã®é·ããªãã¸ã§ã¯ãã«å¯¿å½ã®çããªãã¸ã§ã¯ããã¤ã³ã¸ã§ã¯ããããã¨ãã§ããããã«ãªãã¾ãã
ãã ããã¡ã½ãããã©ãããã¦ããã ããªã®ã§ããã£ã¼ã«ããç´æ¥ã¢ã¯ã»ã¹ãã¦ãã¾ãã¨ãã¡ãªããã§ãã
ããã§ããã°ã£ããã¨ã¯ãThreadLocalãããã«ãã¾ãæ±ããã¨ãããã¨ã§ããã¤ã¾ããDIã³ã³ããã§ã®ã¹ã³ã¼ãã¨ããã®ã¯ãThreadLocalãé è½ããä»çµã¿ã¨ãããã¨ã§ããã
RequestScope! · kishida/tinydi@6061739
ã¾ã¨ã
å®è£
ãã¦ã¿ãã¨ãDIã³ã³ããã¨ããã®ã¯ãJavaã®ãªãã¬ã¯ã·ã§ã³ããã¤ãã³ã¼ãæä½ãThreadLocalã¨ãã£ãããã¾ãç¾ãããªãé¨åãè¦ãé ãã¦ããããªã³ã¼ãã§ã¢ããªã±ã¼ã·ã§ã³ãæ§ç¯ããããã®ä»çµã¿ã¨ãããã¨ããããã¾ãã
ãã®ããã«ãJavaã®æ¨æºã®è¨èªä»æ§ãä»çµã¿ã§ã¯å¯¾å¿ã§ããªãé¨åã代ããã«è¡ã£ã¦ãããã¨ããä»çµã¿ã§ããããã«ãJava以å¤ã®è¨èªã使ã£ã¦ãã人ã«æ½è±¡çãªè¨èã§DIã³ã³ããã®ã¡ãªããã説æãã¦ãä¼ãããªãããã§ããã
ãã¡ããããã 便å©ãªä»çµã¿ãä½ãããã§ããã°ä¾¿å©ã«ãªããã¨ããã¨ããã§ã¯ãªãã¦ããã¯ãããã¸ã®æ½è±¡çãªæå³ä»ãã¨ããããå°ããããããã¹ãè«ãã¨ããã®ã¯å¤§åã§ãSpringã¯ãã®ãããããã£ãããã¦ããããã«å¤ã使ããã¦ããããããã¾ã§çºå±ããã®ã ã¨æãã¾ãã
ã¨ãããã¨ã§ãã¿ããªãªã¬ãªã¬DIã³ã³ããã¨ãªã¬ãªã¬æ¹æ³è«ä½ãã°ããã¨æããï¼
Javaãã¬ã¼ã ã¯ã¼ã¯éçºå ¥é
- ä½è :æ¨æ è¡
- çºå£²æ¥: 2010/07/28
- ã¡ãã£ã¢: åè¡æ¬