依赖注入实践与工具介绍
一、Crosstalk应用启动与概述
1.1 启动Crosstalk
为了让Crosstalk运行起来,我们需要创建一个带有
main
方法的简单类来启动Jetty。将这个类放在
test/
目录下,以区别于正式的应用程序。以下是示例代码:
public class Crosstalk {
public static void main(String... args) throws Exception {
Server jetty = new Server(8080); //start at port 8080
server.addHandler(new WebAppContext("web", "/"));
jetty.start();
jetty.join();
}
}
在上述代码中,
Crosstalk
类创建了一个
Server
实例,代表Jetty Web服务器。我们将其配置为监听8080端口,并将
web/
目录作为资源根目录,同时监听根URL上下文
"/"
。启动Jetty后,它就可以开始处理请求了。使用
join()
方法可以防止应用程序过早退出。启动成功后,在浏览器中访问
http://localhost:8080/login
即可看到登录页面,开始使用Crosstalk。
1.2 Crosstalk应用概述
Crosstalk是一个类似流行的微博服务Twitter的简单应用。它基于Guice构建,使用Hibernate进行数据持久化,Google Sitebricks作为Web框架来显示网页并响应用户输入,同时使用Mort Bay Jetty作为Servlet容器。通过
guice-servlet
集成层来引导注入器,在Web应用部署到Servlet容器时创建和配置注入器。
Crosstalk主要由三个包组成:
-
web
:包含网页类和组件。
-
services
:包含数据和安全服务。
-
tweets
:包含用于数据持久化的领域模型类。
services
包中的所有组件通过接口暴露,其实现细节作为包私有隐藏起来,体现了良好的模块化和松耦合。网页都是请求作用域的,使用
User
类(会话作用域服务)来跟踪当前登录的用户。
LoginPage
确保登录时用户名与
User
服务关联,
HomePage
在适当的时候让用户注销。
为了避免频繁启动和停止持久化引擎带来的高成本操作,我们注册了一个
PersistenceFilter
,使其与Web应用的启动和关闭周期同步。同时,添加了
SecurityInterceptor
来保护未登录用户无法访问主页,这是行为修改或AOP拦截技术的应用。
二、Butterfly容器介绍
2.1 依赖注入的DSL
Butterfly容器是一个开源项目,是Butterfly组件集合的一部分。Butterfly容器使用专门为依赖注入定制的DSL(领域特定语言)——Butterfly容器脚本(BCS)进行配置。BCS与Spring的XML文件类似,但不是XML格式,它结合了标准属性文件(
name = value
)和Java代码的特点,便于Java开发者阅读、编写和学习,也可用于应用程序配置。
2.2 BCS基础
一个BCS脚本文件由一个或多个bean工厂组成。下面是一个简单的配置示例:
myBean1 = * com.myapp.MyBean();
这个配置由五部分组成:
-
工厂ID
(
myBean1
):用于标识工厂,在容器实例中必须唯一,获取实例或从其他工厂引用该工厂时使用。
-
等号
(
=
):表示工厂定义的产品部分开始。
-
实例化模式
(
*
):也称为作用域,BCS目前包含以下实例化模式:
-
*
:每次调用工厂时创建一个新实例。
-
1
:创建一个单例,每次调用工厂时返回该单例。
-
1T
:每个调用工厂的线程创建一个单例,每次调用返回该线程的单例。
-
1F
:为每个提供的输入参数创建一个实例,使用相同输入参数调用工厂时返回该实例。
-
工厂链
(
com.myapp.MyBean()
):定义工厂要返回的对象。
-
分号
(
;
):表示工厂链结束。
2.3 工厂链
在工厂定义的工厂链中,可以调用构造函数、方法,甚至定义局部bean工厂。以下是一个更复杂的示例:
myBean1 = * com.myapp.MyBean1();
myBean2 = * com.myapp.MyBean2("A Text", myBean1)
.setMoreText("more text");
这个配置包含两个工厂:
myBean1
和
myBean2
。
myBean2
的定义展示了一些新特性,它包含两个构造函数参数,第二个参数引用了
myBean1
工厂,意味着从该工厂获取一个实例并注入到构造函数中。工厂链中还包含
setMoreText("more text")
方法调用,用于进一步配置
MyBean2
实例。如果该方法返回一个对象,则工厂返回该对象;如果返回
void
,则返回调用该方法的实例。
2.4 上下文注入
BCS允许通过输入参数进行上下文注入。示例如下:
myBean1 = * com.myapp.MyBean($0).setValue($1);
myBean2 = * myBean1(com.myapp.SomeBean(), "Value Text");
美元符号(
$
)表示要注入输入参数,数字(
0
、
1
等)指定要注入的输入参数。输入参数没有命名或类型,使用时需注意可能出现的类型错误。可以通过单元测试来验证工厂的有效性。
也可以在Java代码中从容器获取bean时提供输入参数:
MyBean myBean = (MyBean)
container.instance("myBean1", new SomeBean(), "Value Text");
如果要注入参数的方法是重载的,容器可能难以确定调用哪个重载方法,此时可以指定注入参数的类型:
myBean1 = * com.myapp.MyBean((long) $0).setValue((String) $1);
2.5 工厂注入
BCS支持注入产品的工厂而不是产品本身,通过在引用工厂名称前加
#
来实现。示例如下:
firstBean = * com.myapp.FirstBean($0).setValue($1);
secondBean = * com.myapp.SecondBean().setFirstBeanFactory(#firstBean);
在
secondBean
工厂中,
firstBean
工厂被注入到
setFirstBeanFactory()
方法中。为了避免代码中对Butterfly容器类的硬引用,Butterfly容器可以将工厂适配到自定义接口,只要接口有
instance()
方法。例如:
public interface FirstBeanFactory {
public FirstBean instance();
}
public class SecondBean {
protected FirstBeanFactory firstBeanFactory = null;
public void setFirstBeanFactory(FirstBeanFactory factory){
this.firstBeanFactory = factory;
}
public void doSomething(){
FirstBean firstBean = this.firstBeanFactory.instance();
}
}
使用
FirstBeanFactory
接口在
SecondBean
中是类型安全的,没有强制类型转换和对Butterfly容器特定类的引用。还可以为
instance()
方法指定类型化参数:
public interface FirstBeanFactory {
public FirstBean instance(long constructorParam, String value);
}
三、SmartyPants-IOC框架
3.1 类+名称键
SmartyPants-IOC是受Java的Google Guice启发,用于构建Adobe Flex和Flash应用的依赖注入框架。它基于三个关键概念:类+名称键、注入器请求(通常通过元数据指定)和注入器规则(使用基于ActionScript的DSL指定)。
在请求注入字段时,大多数情况下需要使用ActionScript元数据注释字段。例如,请求
IServiceInterface
实例的语法如下:
[Inject]
public var myService:IServiceInterface;
如果要查找特定的字符串,如WSDL URL,可以使用以下语法:
[Inject(name="mainWSDL")]
public var myServiceWSDL:String;
这些字段在由SmartyPants-IOC为你构造对象或调用
injector.injectInto(myInstance)
时被注入。SmartyPants-IOC还支持实时注入,结合实时规则时,其行为类似于Flex SDK的数据绑定功能:
//This will be set whenever the source changes
[Inject(name="userName",live)]
public var currentUsername:String;
3.2 注入器规则
注入器规则类似于Guice的绑定,但使用不同的术语以避免与Flex SDK的数据绑定机制混淆。通过DSL告诉注入器要做什么,以下是一些示例:
//Simple singleton rules:
injector.newRule().whenAskedFor(String).named("wsdl")
.useInstance("http://www.server.com/soap/service.wsdl");
injector.newRule().whenAskedFor(IServiceInterface)
.useSingletonOf(MyServiceImpl);
injector.newRule().whenAskedFor(MyConcreteClass).useSingleton();
//"Live" rules act just like <mx:Binding>
injector.newRule().whenAskedFor(String)
.named("userId")
.useBindableProperty(this, "userId");
3.3 启动方式
有两种方式启动注入:
- 在MXML组件中,使用以下代码在
CreationComplete
事件时注入:
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:smartypants="http://smartypants.expantra.net/2008">
<smartypants:RequestInjection/>
<!-- ...Regular code and MXML... -->
</mx:Canvas>
- 在ActionScript中,使用以下代码:
SmartyPants.injectInto(this);
四、相关概念总结
4.1 设计模式与概念
- AOP :通过拦截方法实现行为修改,Guice采用特定方法实现AOP,使用时需谨慎,避免过度使用。
- 构造函数注入 :是一种常见的依赖注入方式,具有利用不可变性、保证对象有效性等优点,但存在循环引用问题。
- 上下文注入 :是部分注入的一种变体,可通过Builders实现。
4.2 其他概念
- 自定义作用域 :在Guice和Spring中都有支持,可根据需求进行定制。
- 并发问题 :可能由作用域扩大引起,需要注意并发访问和同步问题。
4.3 表格总结
| 框架/容器 | 特点 | 配置方式 | 应用场景 |
|---|---|---|---|
| Crosstalk | 基于Guice、Hibernate等构建的Web应用 |
guice-servlet
集成层
| 类似微博的Web应用 |
| Butterfly容器 | 使用BCS进行依赖注入配置 | BCS脚本文件 | Java应用的依赖注入配置 |
| SmartyPants-IOC | 用于Adobe Flex和Flash应用的依赖注入框架 | 基于ActionScript的DSL | Adobe Flex和Flash应用 |
4.4 流程图
graph LR
A[启动Crosstalk] --> B[创建Crosstalk类]
B --> C[启动Jetty服务器]
C --> D[监听端口8080]
D --> E[处理请求]
F[Butterfly容器配置] --> G[编写BCS脚本]
G --> H[定义工厂]
H --> I[实例化对象]
J[SmartyPants-IOC] --> K[定义注入规则]
K --> L[注入依赖]
L --> M[运行应用]
通过以上介绍,我们了解了Crosstalk应用的启动和架构、Butterfly容器的配置方式以及SmartyPants-IOC框架的使用,这些工具和框架在不同的应用场景中发挥着重要作用,帮助开发者实现高效的依赖注入和应用开发。
五、注解相关内容
5.1 常见注解及其作用
在Java开发中,注解是一项重要的特性,以下是一些常见注解及其作用:
| 注解 | 作用 |
| — | — |
|
@Autowired
| 可用于构造函数,实现自动装配依赖,也可替代
@Inject
。 |
|
@Inject
| 用于请求依赖注入,
@Autowired
可在某些情况下替代它。 |
|
@Singleton
| 表示单例模式,使对象在整个应用中只有一个实例,但可能存在缺失的情况。 |
|
@RequestScoped
| 用于指定请求作用域,确保对象在每个请求中是唯一的。 |
|
@SessionScoped
| 用于指定会话作用域,对象在用户会话期间保持一致。 |
|
@Transactional
| 用于标记事务性方法,确保方法执行的原子性和一致性。 |
5.2 注解使用注意事项
- 类型安全 :使用注解时要注意类型安全,避免出现类型错误。例如在使用自定义注解和上下文注入时,输入参数没有明确类型,需要额外注意。
- 避免过度使用 :像AOP相关的注解,使用时要谨慎,避免过度使用导致代码复杂度过高。
六、设计模式与反模式
6.1 设计模式应用
- 抽象工厂模式 :虽然未详细展开,但在依赖注入中,工厂模式可以用于创建对象,实现对象的解耦。
- 适配器模式 :在多个场景中都有应用,如在不同组件之间进行适配,实现接口的转换。
- AOP 与拦截器 :AOP(面向切面编程)通过拦截方法实现横切关注点的处理,如日志记录、安全检查等。Guice有自己的AOP实现方式,使用时要注意避免过度使用。
6.2 反模式分析
- 黑盒反模式 :表现为生命周期、配置等方面的问题,如刚性配置、脆弱的基础类等,会导致代码难以维护和扩展。
- 单例反模式 :单例模式如果使用不当,可能会导致代码耦合度增加,影响可测试性和可维护性。
6.3 设计模式与反模式流程图
graph LR
A[设计模式] --> B[抽象工厂模式]
A --> C[适配器模式]
A --> D[AOP与拦截器]
E[反模式] --> F[黑盒反模式]
E --> G[单例反模式]
B --> H[对象创建解耦]
C --> I[接口转换适配]
D --> J[横切关注点处理]
F --> K[刚性配置问题]
F --> L[脆弱基础类问题]
G --> M[代码耦合度增加]
七、应用开发中的其他重要概念
7.1 应用逻辑与基础设施逻辑分离
应用逻辑是指实现业务功能的核心代码,而基础设施逻辑则包括数据库连接、日志记录等与业务无关的代码。将两者分离可以提高代码的可维护性和可测试性。例如在Crosstalk应用中,将数据访问、安全服务等基础设施逻辑与网页显示等应用逻辑分开,使得代码结构更加清晰。
7.2 并发与同步
并发问题在多线程应用中很常见,可能由作用域扩大等原因引起。为了避免并发问题,需要注意原子操作和同步机制。例如在访问共享资源时,要确保操作的原子性,避免数据不一致。
7.3 数据库相关
- 数据库连接池 :为了提高数据库访问效率,通常会使用数据库连接池,如在Crosstalk应用中使用数据库连接池来管理数据库连接。
- 对象与数据库映射 :将对象映射到数据库表是常见的操作,如使用Hibernate等ORM框架实现对象与数据库行的映射。
7.4 相关概念关系图
graph LR
A[应用开发] --> B[应用逻辑与基础设施逻辑分离]
A --> C[并发与同步]
A --> D[数据库相关]
B --> E[提高可维护性]
B --> F[提高可测试性]
C --> G[避免并发问题]
D --> H[数据库连接池]
D --> I[对象与数据库映射]
八、总结与展望
8.1 总结
通过对Crosstalk应用、Butterfly容器、SmartyPants-IOC框架以及相关设计模式、注解等内容的介绍,我们了解到不同工具和框架在依赖注入和应用开发中的作用。Crosstalk应用展示了如何将多种技术结合构建一个完整的Web应用;Butterfly容器通过BCS脚本实现灵活的依赖注入配置;SmartyPants-IOC框架为Adobe Flex和Flash应用提供了依赖注入解决方案。同时,我们也学习了各种设计模式和反模式,以及应用开发中的重要概念,如并发、数据库处理等。
8.2 展望
在未来的开发中,依赖注入和相关技术将继续发挥重要作用。随着技术的不断发展,我们可以期待更高效、更灵活的依赖注入框架和工具的出现。同时,对于并发、安全等问题的处理也将更加成熟和完善,为开发者提供更好的开发体验和更稳定的应用程序。开发者需要不断学习和掌握这些新技术,以适应不断变化的开发需求。
总之,依赖注入技术及其相关工具和概念为现代软件开发提供了强大的支持,帮助开发者构建出更加模块化、可维护和可测试的应用程序。
超级会员免费看

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



