<!-- /* default css */ table { font-size: 1em; line-height: inherit; border-collapse: collapse; } tr { text-align: left; } div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px; } p { margin: 0px; } pre { font-family: Courier New; white-space: pre-wrap; margin:0; } body { margin: 6px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff; } img { -moz-force-broken-image-icon: 1; } @media screen { html.pageview { background-color: #f3f3f3 !important; overflow-x: hidden; overflow-y: scroll; } body { min-height: 1100px; counter-reset: __goog_page__; } * html body { height: 1100px; } .pageview body { border-top: 1px solid #ccc; border-left: 1px solid #ccc; border-right: 2px solid #bbb; border-bottom: 2px solid #bbb; width: 648px !important; margin: 15px auto 25px; padding: 40px 50px; } /* IE6 */ * html { overflow-y: scroll; } * html.pageview body { overflow-x: auto; } /* Prevent repaint errors when scrolling in Safari. This "Star-7" css hack targets Safari 3.1, but not WebKit nightlies and presumably Safari 4. That's OK because this bug is fixed in WebKit nightlies/Safari 4 :-). */ html*#wys_frame::before { content: '/A0'; position: fixed; overflow: hidden; width: 0; height: 0; top: 0; left: 0; } .writely-callout-data { display: none; } .writely-footnote-marker { background-image: url('MISSING'); background-color: transparent; background-repeat: no-repeat; width: 7px; overflow: hidden; height: 16px; vertical-align: top; -moz-user-select: none; } .editor .writely-footnote-marker { cursor: move; } .writely-footnote-marker-highlight { background-position: -15px 0; -moz-user-select: text; } .writely-footnote-hide-selection ::-moz-selection, .writely-footnote-hide-selection::-moz-selection { background: transparent; } .writely-footnote-hide-selection ::selection, .writely-footnote-hide-selection::selection { background: transparent; } .writely-footnote-hide-selection { cursor: move; } /* Comments */ .writely-comment-yellow { background-color: #ffffd7; } .writely-comment-orange { background-color: #ffe3c0; } .writely-comment-pink { background-color: #ffd7ff; } .writely-comment-green { background-color: #d7ffd7; } .writely-comment-blue { background-color: #d7ffff; } .writely-comment-purple { background-color: #eed7ff; } .br_fix span+br:not(:-moz-last-node) { position:relative; left: -1ex } #cb-p-tgt { font-size: 8pt; padding: .4em; background-color: #ddd; color: #333; } #cb-p-tgt-can { text-decoration: underline; color: #36c; font-weight: bold; margin-left: 2em; } #cb-p-tgt .spin { width: 16px; height: 16px; background: url(//ssl.gstatic.com/docs/clipboard/spin_16o.gif) no-repeat; } } h6 { font-size: 8pt } h5 { font-size: 8pt } h4 { font-size: 10pt } h3 { font-size: 12pt } h2 { font-size: 14pt } h1 { font-size: 18pt } blockquote {padding: 10px; border: 1px #DDD dashed } .webkit-indent-blockquote { border: none; } a img {border: 0} .pb { border-width: 0; page-break-after: always; /* We don't want this to be resizeable, so enforce a width and height using !important */ height: 1px !important; width: 100% !important; } .editor .pb { border-top: 1px dashed #C0C0C0; border-bottom: 1px dashed #C0C0C0; } div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em; } /* Table of contents */ .editor div.writely-toc { background-color: #f3f3f3; border: 1px solid #ccc; } .writely-toc > ol { padding-left: 3em; font-weight: bold; } ol.writely-toc-subheading { padding-left: 1em; font-weight: normal; } /* IE6 only */ * html writely-toc ol { list-style-position: inside; } .writely-toc-none { list-style-type: none; } .writely-toc-decimal { list-style-type: decimal; } .writely-toc-upper-alpha { list-style-type: upper-alpha; } .writely-toc-lower-alpha { list-style-type: lower-alpha; } .writely-toc-upper-roman { list-style-type: upper-roman; } .writely-toc-lower-roman { list-style-type: lower-roman; } .writely-toc-disc { list-style-type: disc; } /* Ordered lists converted to numbered lists can preserve ordered types, and vice versa. This is confusing, so disallow it */ ul[type="i"], ul[type="I"], ul[type="1"], ul[type="a"], ul[type="A"] { list-style-type: disc; } ol[type="disc"], ol[type="circle"], ol[type="square"] { list-style-type: decimal; } /* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } .endnotes { page: endnote; } /* MLA specifies that endnotes title should be 1" margin from the top of the page. */ @page endnote { margin-top: 1in; } callout.google_footnote { display: prince-footnote; footnote-style-position: inside; /* These styles keep the footnote from taking on the style of the text surrounding the footnote marker. They can be overridden in the document CSS. */ color: #000; font-family: Verdana; font-size: 10.0pt; font-weight: normal; } /* Table of contents */ #WritelyTableOfContents a::after { content: leader('.') target-counter(attr(href), page); } #WritelyTableOfContents a { text-decoration: none; color: black; } /* Comments */ .writely-comment-yellow { background-color: #ffffd7; } .writely-comment-orange { background-color: #ffe3c0; } .writely-comment-pink { background-color: #ffd7ff; } .writely-comment-green { background-color: #d7ffd7; } .writely-comment-blue { background-color: #d7ffff; } .writely-comment-purple { background-color: #eed7ff; } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } @footnotes { border-top: solid black thin; padding-top: 8pt; } } /* end default print css */ /* custom css */ /* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } /* end ui edited css */ /* editor CSS */ .editor a:visited {color: #551A8B} .editor table.zeroBorder {border: 1px dotted gray} .editor table.zeroBorder td {border: 1px dotted gray} .editor table.zeroBorder th {border: 1px dotted gray} .editor div.google_header, .editor div.google_footer { border: 2px #DDDDDD dashed; position: static; width: 100%; min-height: 2em; } .editor .misspell {background-color: yellow} .editor .writely-comment { font-size: 9pt; line-height: 1.4; padding: 1px; border: 1px dashed #C0C0C0 } /* end editor CSS */ -->
Drop 是一个开源的 JSR-330(Dependency Injection for Java)参考实现,已通过 JSR-330 TCK 测试。该项目旨在构建一个符合 JSR-330 的最小化实现,使得新手能够更快了解 Java 依赖注入实现原理以及了解 Java 依赖注入标准规范。Drop 使用的是 Java 反射来进行依赖注入,没有使用代码生成来实现依赖注入。
例如:
final Configurer configurer = injector.getConfigurer();
scoped(new DefaultScopedLiteral()).
qualified(new HelloLiteral());
在 JSR-330 中,Named 也是一种 Qualifier,所以上述例子也可以这样写:
qualified (new NamedLiteral("helloSpeaker"), new HelloLiteral());
注入点检查
Drop 使用类型安全的依赖解析算法,类型安全指的就是:
现在,我们添加一个 Speaker 实现类:
SimpleBean.java:
@Override
protected void resolveDependencies(final Object reference)
throws Exception {
final Class<?> superclass = reference.getClass().getSuperclass();
resolveSuperclassFieldDependencies(reference, superclass);
resolveSuperclassMethodDependencies(reference, superclass);
resolveCurrentclassFieldDependencies(reference);
resolveCurrentclassMethodDependencies(reference);
}
具体实现为 Java 类层次递归实现,请参考 源码 。
well-formed
Drop 简介
Drop 简介
转载请保留作者信息:
作者:88250
时间:2009 年 11 月 30 日Drop 是一个开源的 JSR-330(Dependency Injection for Java)参考实现,已通过 JSR-330 TCK 测试。该项目旨在构建一个符合 JSR-330 的最小化实现,使得新手能够更快了解 Java 依赖注入实现原理以及了解 Java 依赖注入标准规范。Drop 使用的是 Java 反射来进行依赖注入,没有使用代码生成来实现依赖注入。
Drop 注入器配置
Drop 提供两种方式配置组件(Bean):- Java 注解
例如:
@Named("helloSpeaker")
@Hello // 限定器
@SessionScoped // 作用域
public class HelloSpeaker {
public String say() {
return "Hello!";
}
} - Builder-style APIs
Configurer.createBean(concreteClass<T>) : Bean<T>
Bean.<T>named(stringName) : Bean<T>
Bean.<T>scoped(scopeAnnotation) : Bean<T>
Bean.<T>qualified(qualifierAnnotation, qualifierAnnotation...) : Bean<T>
例如:
final Configurer configurer = injector.getConfigurer();
configurer.createBean(HelloSpeaker.class).
named("helloSpeaker").
scoped(new DefaultScopedLiteral()).
qualified(new HelloLiteral());
在 JSR-330 中,Named 也是一种 Qualifier,所以上述例子也可以这样写:
configurer.createBean(HelloSpeaker.class).
named("helloSpeaker").
scoped(new DefaultScopedLiteral()).
named("helloSpeaker").
qualified (new NamedLiteral("helloSpeaker"), new HelloLiteral());
注入点检查
Drop 使用类型安全的依赖解析算法,类型安全指的就是:
-
- 不使用文本内容进行组件依赖配置
- 依赖类型 + 限定器 = 类型安全
-
注入点
注入点描述了需要进行依赖注入(标注了 @Inject)的元素信息。依赖注入有三个方法:字段注入,构造器注入,方法注入。据此,注入点可以分为两类,字段注入点,参数注入点。 -
需要的类型
需要的类型指的是被注入实例的的类型。该信息包含在注入点描述中。 -
需要的限定器
需要的限定器指的是注入点中描述的限定器。当注入点同时存在需要的限定器与需要的类型时,依赖注入容器可以进行类型安全的依赖查找与注入。 -
依赖不满足
该情况指的是依赖注入容器在进行注入点依赖查找时未从容器中找到满足注入点条件的情况。 -
依赖混淆
该情况指的是依赖注入容器在进行注入点依赖查找时从容器中查找到多于一个满足注入点条件的情况。 - 依赖检查
依赖检查指的就是检查依赖注入器中的所有注入点是否合法以及是被否满足,发生在容器配置后。如果满足,则注入器可以进行依赖注入,如果不满足,则抛出检查异常。
例如,形如 @Inject Speaker nightSpeaker 的注入点,其需要的类型为:Speaker;需要的限定器为空集。形如 @Inject @Night Speaker nightSpeaker 的注入点,其需要的类型为:Speaker;需要的限定器为 @Night。该注入点为合法注入点,但是否能满足依赖还需要根据注入器的配置进行检查。
一个合法可注入的字段:
一个合法可注入的方法:
Drop 目前还没有全部实现所有上述条件的检查。
注入点合法性检查
一个合法可注入的构造器:- 被 @Inject 标注。
- 接受 0 个或多个参数,所有参数都作为参数注入点。
- 在同一个类上只能存在一个可注入的构造器(只能有一个构造器被 @Inject 标注),如果一个类有且仅有一个默认构造器(public 修饰,无参数),不管是否标注 @Inject,注入器都将调用该默认构造器。
- 不能是带类型参数的构造器。例如:<T> TypeName(T t) 不能进行注入。
一个合法可注入的字段:
- 被 @Inject 标注。
- 不能是 final 的。
- 不能是类型变量。例如 T field 不能进行注入。
一个合法可注入的方法:
- 被 @Inject 标注。
- 不能是 abstract 的。
- 接受 0 个或多个参数,所有参数都作为参数注入点。
- 不能是带类型参数的方法。例如:<T> void method(T t) 不能进行注入。
Drop 目前还没有全部实现所有上述条件的检查。
注入点依赖满足检查
JSR-330 规范将 @Named 定义为了一个限定器,并且有一个 String 类型的属性。这样,除了使用类型安全的依赖解析算法,也可以使用命名解析算法。下面,我们通过一个具体的例子来看看如何对注入点进行依赖满足检查。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.FIELD})
@Qualifier
public @interface Night {}
public interface Speaker {
String say();
}
public interface DarkernessSpeaker extends Speaker {}
@Named("nightSpeaker")
@Night
public class NightSpeaker implements DarknessSpeaker {
@Override
public String say() {
return "Night!";
}
}
public class SpeakerService {
@Inject
private Speaker nightSpeaker1;
@Inject
private DarknessSpeaker nightSpeaker2;
@Inject
private NightSpeaker nightSpeaker3;
@Inject
@Night
private Speaker nightSpeaker4;
@Inject
@Named("nightSpeaker")
private Speaker nightSpeaker5;
@Inject
@Named("nightSpeaker")
@Night
private Speaker nightSpeaker6;
}
我们逐个分析 SpeakerService 类的字段注入点依赖检查。注意,在整个依赖注入容器中,目前有且仅有一个 Speaker 接口的实现,即 NightSpeaker。因此,对于:
- @Inject private Speaker nightSpeaker1;
该字段是可依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据接口 Speaker 查找到其唯一的实现 NightSpeaker。 - @Inject private DarknessSpeaker nightSpeaker2;
该字段是可以依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据抽象类 DarknessSpeaker 查找到其唯一的实现 NightSpeaker。 - @Inject private NightSpeaker nightSpeaker3;
该字段是可以依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据具体类 DarknessSpeaker 查找到其唯一的实现 NightSpeaker。 - @Inject @Night private Speaker nightSpeaker4;
该字段是可以依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据接口 Speaker 与限定器 @Night 查找到其唯一的实现 NightSpeaker。 - @Inject @Named("nightSpeaker") private Speaker nightSpeaker4;
该字段是可以依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据接口 Speaker 与限定器 @Named("nightSpeaker") 查找到其唯一的实现 NightSpeaker。 - @Inject @Named("nightSpeaker") @Night private Speaker nightSpeaker4;
该字段是可以依赖解析的,不存在依赖不满足或依赖混淆情况。注入器可以根据接口 Speaker 与限定器集 {@Named("nightSpeaker"), @Night} 查找到其唯一的实现 NightSpeaker。
现在,我们添加一个 Speaker 实现类:
public class HelloSpeaker implements Speaker {
@Override
public String say() {
return "Night!";
}
}
}
此时,对于 SpeakerService 类的字段注入点 @Inject private Speaker nightSpeaker1; 来说,该注入点是不可依赖解析的,存在依赖混淆情况。注入器在根据接口 Speaker 查找时,将找到两个实现:NightSpeaker 与 HelloSpeaker。注入器无法判别该用哪一个类的实例进行依赖注入。
依赖注入
注入顺序
JSR-330 规定了依赖注入的顺序,如下(忽略了静态成员注入):- 构造器注入
- 父类字段注入
- 父类方法注入
- 子类字段注入
- 子类方法注入
注入实现
算法实现了遵循 JSR-330 的依赖注入顺序:SimpleBean.java:
@Override
protected void resolveDependencies(final Object reference)
throws Exception {
final Class<?> superclass = reference.getClass().getSuperclass();
resolveSuperclassFieldDependencies(reference, superclass);
resolveSuperclassMethodDependencies(reference, superclass);
resolveCurrentclassFieldDependencies(reference);
resolveCurrentclassMethodDependencies(reference);
}
具体实现为 Java 类层次递归实现,请参考 源码 。
中英术语对照表
| 英文 | 中文 |
| Annotation | 注解 |
| Qulifier | 限定器 |
| Scope | 作用域 |
| Bean | 组件 |
| Injection Point | 注入点 |
| Required Type | 需要的类型 |
| Required Qualifiers | 需要的限定器 |
well-formed
8668

被折叠的 条评论
为什么被折叠?



