本文档是关于Spring框架开发风格分析性文档。包括:基本概念、设计原则、设计规范、重要功能分析、关键类分析等。
本文档适合所有Java开发人员。
a) 装配:创建系统组件之间协作关系的这个动作。
b) Spring坚持的信念:
i. 好的设计比实现技术重要。
ii. 通过接口松散耦合的JavaBeans是个很好的模型。
iii. 代码应该容易测试。
c) Spring的特性:
i. Spring:是一个轻量级的IoC和AOP容器框架。
ii. 反向控制IoC:对象是被动接收依赖类而不是主动的查找。可以将IoC理解为JNDI的反转-对象不是从容器中查找他的依赖类,而是容器在实例化对象的时候主动将它的依赖类注入给它。
iii. AOP面向切面:系统对象只做他们该做的-业务逻辑,不负责(或关心)其他系统的问题(如日志和事务支持)。
1. AOP经常定义为编程技术,用来在系统中提升业务的分离。
2. 系统服务如日志、事务管理和安全经常融入到一些其他功能模块中。这些系统服务通常叫做交叉业务。它分布在多个组件中,给代码带来双重复杂性。
a) 如果改变业务规则,需要到各个模块中去修改。即使抽象为一个模块,其他地方也得调用个方法,该方法还是分布到很多地方。
b) 组件可能因为那些与核心业务无关的代码变得凌乱。
d) AOP帮助将这些服务模块化,并把他们声明式的应用在需要它们的地方。核心业务甚至不知道他们的存在。
i. 容器:包含并管理系统对象的生命周期和配置。
ii. 框架:使用简单的组件配置组合成一个复杂的系统。
Spring是代码:更加清晰、更容易管理、更容易测试。
e) POJO:Plain Old Java Object, 或者:POJI: Plain Old Java Interface
1.功能类和工具类分离的原则。
4.1.1 命名规范
l
包名都采用小写字母。
org.springframework.beans.propertyeditors
l 类的命名要清晰准确。允许一定的长度。例如:JdbcUpdateAffectedIncorrectNumberOfRowsException
4.1.2 划分方式
l
core
包。与功能相关,是模块或子系统核心类
l support包。是功能支撑性的类,来辅助或扩展core包中的类。例如:org.springframework.jdbc.core.support.core. AbstractSqlTypeValue
org.springframework.jdbc.support.CustomSQLErrorCodesTranslation
l
utils
包。一些通用的工具,例如:日期时间工具,通常命名以
utils
结尾,或者是
helper
结尾。例如
: org.springframework.util. NumberUtils
。
l
exception
包。存在异常类,对于所有可能的异常,根据分类,都可以单独进行命名。
1.
Operations
接口类
i.
exposing a set of common JDBC operations, whose interface is simplified
through
the
use
of
varargs
and
autoboxing.
ii.
例如:
SimpleJdbcOperations
2.
Accessor
辅助类
i.
不以直接使用为目的。
Not intended to be used directly
ii.
定义了一些主类或应用类所需要的一些属性、工具方法。例如:异常转换、基本参数等。
iii.
它通常使用于在接口和具体实现类之间。
iv.
例如:
JdbcTemplate
、
JdbcOperations
、
JdbcAccessor
3.
Template
模版类
i.
采用模版执行函数。定义操作的步骤。具体的业务逻辑,由子类实现,或内部类形式实现。
ii.
采用回调机制。具体的实现逻辑在回调接口的子类实现。例如:
ConnectionCallback
iii.
采用重载方式,支持多种参数调用形式。
iv.
处理异常,转化为统一格式的异常形式。
This is the central class in the JDBC core package.</b>
*
It
simplifies
the
use
of
JDBC
and
helps
to
avoid
common
errors.
*
It
executes
core
JDBC
workflow,
leaving
application
code
to
provide
SQL
and
extract
results.
v.
例如:
SimpleJdbcTemplate
、
JdbcTemplate
、
4.
Support
支持类
i.
通常封装一些工具方法,方法直接委托给工具类去实现。
ii.
可以是抽象类的形式,子类可以进行扩展。例如:
DaoSupport
、
JdbcDaoSupport
中的,
getExceptionTranslator
、
getConnection
等方法。
iii.
可以把其它组织发布的类作为自己的属性。然后添加自己的公那。
iv.
采用
Delegate
设计方式,启发,如果项目中,需要一些帮助类,就可以采用
delegate
方式,而不是采用继承的形式,这样可以保证独立演化的独立性。
v.
例如:
SimpleJdbcDaoSupport
、
CommonsFileUploadSupport
,
5.
Resolver
分解或解析类
i.
一些解析功能。解析字符串、请求格式等
ii.
例如:
MultipartResolver
、
CommonsPortletMultipartResolver
继承于
CommonsFileUploadSupport
iii.
如果使用文件上传功能,可以配置下面类:
<!-- MultipartResolver for parsing file uploads, mplementation for
Commons FileUpload -->
<
bean
id
=
"multipartResolver"
class
=
"org.springframework.web.multipart.commons.CommonsMultipartResolver"
/>
6.
Parser
i.
ComponentScanBeanDefinitionParser BeanDefinitionParser
7.
Translator
转换类或翻译类
i.
完成转换功能
ii.
可以定义为接口的形式。由具体的子类进行实现。
iii.
例如:
SQLExceptionTranslator
8.
Custom
客户化类
i. 建议命名:custom
ii. 例如:
9.
Aware
感知类
i.
ApplicationContextAware Interface
to
be
implemented
by
any
object
that
wishes
to
be
notified
of
the
{@link ApplicationContext}
that
it
runs
in.
ii.
例如:
ApplicationContextAware
、ServletContextAware、ServletConfigAware
10.
Job
工作类
i.
对于定时性的类,可以表明该类的用途。
11.
Impl
实现类
i.
具体实现业务逻辑的类。当实现接口或抽象类时,可以添加这个后缀。
12.
Listener
监听器类
i.
监听某个事件的发生,如果发生,就可以出发一定的动作。
ii.
例如:
ContextLoaderListener extends ServletContextListener
完成
WebApplicationContext
初始化。
ContextLoader
类完成实际的初始化工作。
13.
Configurer
配置类
i.
提供配置参数、初始化数据等功能。
ii.
例如:
PropertyPlaceholderConfigurer
通常在
applicationContext.xml
配置属性文件、
Log4jConfigListener
。
14. Context 上
下文类
i.
提供了配置功能。包括:能运行的基本属性信息、基本参数信息等。
ii.
高层通常以接口形式提供。
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver
该接口继承不同的接口,代表有能力去
BeanFactory
、有能力装载文件资源、能够发布事件、解析参数、支持国际化等
iii.
15.
Adapter
适配器类
i.
提供一个转换功能。可以使得原来不能交互的类通过该
Adapter
进行交互。
ii. 例如:
NativeJdbcExtractorAdapter extends implements NativeJdbcExtractor
16.
Extractor
分离器、解析类
i.
ii.
例如:
ResultSetExtractor
、
Object extractData(ResultSet rs) C3P0NativeJdbcExtractor
17.
Definition
定义类
i.
定义一组常量和一些方法。
ii.
可以是接口的形式。例如:
TransactionDefinition
18.
Editor
编辑类
i.
完成解析字符串,按照预先定义的方式解析。
ii.
例如:
TransactionAttributeEditor
*
<p>
A
"+"
before
an
exception
name
substring
indicates
that
transactions
should
commit
*
even
if
this
exception
is
thrown;
a
"
-
"
that
they
should
roll
back.
iii.
19.
Façade
门面类
i.
提供了访问内部实现逻辑的入口。
ii.
例如:
PetStoreFacade
20.
Assert
断言类
i.
验证执行条件是否合法。
ii.
Apache commons
有此工具类
iii.
实例:
ModelAndViewAssert assertCompareListModelAttribute
21.
Handler
处理器类
i.
完成实际的业务逻辑。
Spring
的
jdbcTemplate
中使用这种类,完成回调工作。
ii.
例如:RowCallbackHandler 种的p
rocessRow
22. Multi
caster
广播类
i.
管理监听器,可以增加、删除、删除监听器,
ii.
Multicast the given application event to appropriate listeners.
广播一个事件给某个监听器。
iii.
例如:
ApplicationEventMulticaster
23.
Listener
监听器
Observer design pattern.
i.
处理监听事件
Handle an application event.
ii.
例如:
ApplicationListener void onApplicationEvent(ApplicationEvent event);
24.
Publisher
发布者类
i.
发布某个事件给全部的监听器。
ii.
例如:
ApplicationEventPublisher void publishEvent(ApplicationEvent event);
25.
Executor
执行者类
i.
执行任务
ii.
例如:
java.util.concurrent.Executor
、
TaskExecutor void execute(Runnable task);
26.
Processor
处理器类
i.
对某个对象或对某个事件进行处理
ii.
例如:
BeanFactoryPostProcessor void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
27.
Generic
普通类、一般类
i.
完成通用的功能
ii.
例如:
GenericApplicationContext
28.
Default
缺省类
i.
完成缺省功能
ii.
例如:
DefaultListableBeanFactory
29.
Tag
标签类
i.
30.
Delegating
委托类
i.
提供工具方法
ii.
实例:
DelegatingActionProxy
、
DelegatingActionUtils
31.
PlugIn
插件类
i.
实例:
32.
Illegal
非法类
i.
例如:
IllegalStateException
ii.
33.
Decoder
解码类
i.
实例:
HtmlCharacterEntityDecoder
34.
References
参考类
i.
例如:
HtmlCharacterEntityReferences
ii.
35.
Advisor
i.
实例:
PersistenceExceptionTranslationAdvisor
36.
Resource
资源类
i.
提供访问和操作资源的功能。
资源比如:各种格式的文件、
URL
、类路径
ii.
实例:
ResourceLoader
37.
Loader
装载类
i.
实例:
ClassLoader
38.
Scanner
扫描类
i.
A bean definition scanner that detects bean candidates on the classpath,
ii.
ClassPathBeanDefinitionScanner
39.
Registry
注册类
i.
BeanDefinitionRegistry
40.
Visitor
访问者类
i.
AnnotationMetadataReadingVisitor
41.
1. 从重构的角度上将,推荐使用getter/setter方式。this.propertyName访问形式,spring中大量使用这种方式,例如:ListImagesQuartzJob
2. 对于有方向性的属性,可以命名为:
from
、
to
、
replayTo
、
cc
3. 对于时间性的,可以以elapsed开头,例如:elapsedTime
4. 缺省值,default 例如:Properties defaultStrategies
5. 为谁产生什么结果,例如:@Transactional(rollbackFor=Exception.class, noRollbackFor={IOException.class})
6. 参数 Log4jWebConfigurer REFRESH_INTERVAL_PARAM
7. 常量定义 HttpServlet METHOD_DELETE
8. 范围 SCOPE_REQUEST SCOPE_APPLICATION
9. 根属性
String
ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
= WebApplicationContext.
class
.getName() +
".ROOT"
;
10. 方式 pattern 如果有新旧关系,要命名两个oldPattern newPattern
11. 类型 type
12. 类变量 clazz
1. 对于模版方法,要注释是该方法。通常以do开头,子类完成实际的逻辑。例如:doGetNativeConnection。 也可以在本类中完成实际逻辑,例如:getConnection () { doGetConnect()}
2. 接口需要对函数添加注释,子类没有必要。否则,维护不方便。Eclipse方便的支持看接口或父类中的注释。
3. 对于函数的参数,如果不解释,就不要现显示在函数上面,否则,没有意义。如果需要添加时,也不晚。
4. 在一个函数中,调用其他关键函数时,要添加一定的注释。
5. 如果标识参数非法,可以采用reject开头。例如;rejectIfNotEqualExactLength
6. 对于判断性的函数,采用is开头。例如: isExistUser
7. 对于加载参数,开头命名为:load 例如:loadParentContext
8. 初时化信息,启动的等。开头命名为:init 、setUp例如:Log4jConfigListener中的initLogging
9. 关闭服务、释放资源等。Close、Shutdown 、release、tearDown例如:Log4jWebConfigurer.shutdownLogging, releaseConnection
10. 创建服务。Create 例如:createConnectionProxy
11. 被初始化、被销毁。Initialized 例如:contextInitialized、contextDestroyed
12. 准备做什么。AbstractTransactionalDataSourceSpringContextTests 类中的,onSetUpBeforeTransaction、onTearDownAfterTransaction
13. 包含? containsWhitespace containsLocalBean
14. 存在?有?hasFieldErrors
15. 执行 execute
16. 回调类中的方法。 doInContext
17. 在之后、之前。 Before , after , afterPropertiesSet
18. 处理 。 RowCallbackHandler 种的p
rocessRow
19. 预、后处理 preProcess postProcess postBeforeInitializtion
20.
21.
提取、解析ResultSetExtractor ext
ractData
、
parseData
22.
如果可能 createLinkedSetIfPossible
23. 刷新或装载 refresh
Load
or
refresh
the
persistent
representation
of
the
configuration,
*
which
might
an
XML
file,
properties
file,
or
relational
database
schema.
24. 调用多个类或动作, 要添加s,invokeBeanFactoryPostProcessors
25. 注册 registerListeners
26. 实例化 preInstantiate
27. 预先 pre
28. 临时 temp
29. 添加、删除、代替 ,attributeAdded、attributeRemoved、attributeReplaced
30. 在操作后处理 postProcessAfterInitialization
31. 发布 publishEvent
32. 内部的 Internal 。RequestContextAwareTag doStartTagInternal
33.
【计】换码 Escape
htmlEscape
34. 执行脚本 executeSqlScript
1.Enum方式。例如:
propagation
2.工具类可以定义常量。WebUtils
1. 对于catch到的所有异常,对于实例都可以命名为:ex
catch
(MailException ex) {
throw
ex;
}
2. 异常的命名 完全描述操作的意图CannotGetJdbcConnectionException 、
NameNotFoundException
1. 提供一些计算、查询、统计等工具性方法。
2. 可以广泛的被其他类进行引用。
3. 验证参数类,Spring有自己的Validator 和Errors相互配合使用
4. 通常以utils结尾。例如:ValidationUtils、WebApplicationContextUtils
5.
1.
对函数的解释,通常是在接口中描述,对于子类要实现时,可以根据具体的情况,添加注释,如果父类,已经表述的非常清楚,子类可以不用添加注释。
2.
例如:
CommonsMultipartResolver
中的
isMultipart
、
resolveMultipart
3.
常用的注释形式
i.
Return <code>false</code> by default.
ii.
Local DataSource that works in any environment
iii.
A constant indicating that
iv.
Phone number is required.
v.
Root WebApplicationContext: initialization completed in
1. e.g. e.g. for updates when coming
back from the GUI, is straightforward, as the instance has kept its identity.
2. Note that Hibernate works on unmodified plain Java objects, performing dirty
detection via copies made at load time.
Note: is same
3. assumably assumably often as anonymous classes within a method implementation.
4. if any 即便要 Apply the current transaction timeout, if any, to the given
Hibernate Query object
5. i.e. Allows for returning a result object created within the callback, i.e.
a domain object or a collection of domain objects.
6. non-null
7. Utility methods for managing versions and timestamps
8. Has the following responsibilities:
9. // do nothing
10. named 指定的
1.
LocalVariableTableParameterNameDiscoverer
ParameterNameDiscoverer
Uses ObjectWeb's ASM library for analyzing class files.
DelegatingActionUtils
/**
*
Perform
a
scan
within
the
specified
base
packages.
*
@param
basePackages
the
packages
to
check
for
annotated
classes
*
@return
number
of
beans
registered
*/
public
int
scan(String... basePackages) {
int
beanCountAtScanStart =
this
.
registry
.getBeanDefinitionCount();
doScan(basePackages);
// Register annotation config processors, if necessary.
if
(
this
.
includeAnnotationConfig
) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(
this
.
registry
);
}
return
this
.
registry
.getBeanDefinitionCount() - beanCountAtScanStart;
}
1.通常为接口提供了一些默认实现、通用实现。每一个类都有自己的责任。
a) ContextLoader
b) AbstractContextLoader
c) AbstractGenericContextLoader
2.
5.5 向JVM注册回调
AbstractApplicationContext.registerShutdownHook
Register a shutdown hook with the JVM runtime,
SimpleJdbcTestUtils
/**
*
<p>
*
Execute
the
given
SQL
script.
*
</p>
*
*
@param
simpleJdbcTemplate
The
SimpleJdbcTemplate
with
which
to
perform
*
JDBC
operations.
*
@param
resourceLoader
The
resource
loader
(e.g.,
an
*
{@link ApplicationContextException}
)
with
which
to
load
the
SQL
*
script.
*
@param
sqlResourcePath
Spring
resource
path
for
the
SQL
script.
Should
*
normally
be
loaded
by
classpath.
There
should
be
one
statement
per
*
line.
Any
semicolons
will
be
removed.
<b>
Do
not
use
this
method
to
*
execute
DDL
if
you
expect
rollback.
</b>
*
@param
continueOnError
whether
or
not
to
continue
without
throwing
an
*
exception
in
the
event
of
an
error.
*
@throws
DataAccessException
if
there
is
an
error
executing
a
statement
*
and
continueOnError
was
<code>
false
</code>
.
*/
public
static
final
void
executeSqlScript(
final
SimpleJdbcTemplate simpleJdbcTemplate,
final
ResourceLoader resourceLoader,
final
String sqlResourcePath,
final
boolean
continueOnError)
throws
DataAccessException {
if
(
logger
.isInfoEnabled()) {
logger
.info(
"Executing SQL script '"
+ sqlResourcePath +
"'"
);
}
final
long
startTime = System.currentTimeMillis();
final
List<String> statements =
new
LinkedList<String>();
final
Resource res = resourceLoader.getResource(sqlResourcePath);
try
{
final
LineNumberReader lnr =
new
LineNumberReader(
new
InputStreamReader(res.getInputStream()));
String currentStatement = lnr.readLine();
while
(currentStatement !=
null
) {
currentStatement = StringUtils.replace(currentStatement,
";"
,
""
);
statements.add(currentStatement);
currentStatement = lnr.readLine();
}
for
(
final
Iterator<String> itr = statements.iterator(); itr.hasNext();) {
final
String statement = itr.next();
try
{
final
int
rowsAffected = simpleJdbcTemplate.update(statement);
if
(
logger
.isDebugEnabled()) {
logger
.debug(rowsAffected +
" rows affected by SQL: "
+ statement);
}
}
catch
(
final
DataAccessException ex) {
if
(continueOnError) {
if
(
logger
.isWarnEnabled()) {
logger
.warn(
"SQL: "
+ statement +
" failed"
, ex);
}
}
else
{
throw
ex;
}
}
}
final
long
elapsedTime = System.currentTimeMillis() - startTime;
if
(
logger
.isInfoEnabled()) {
logger
.info(
"Done executing SQL script '"
+ sqlResourcePath +
"' in "
+ elapsedTime +
" ms."
);
}
}
catch
(
final
IOException ex) {
throw
new
DataAccessResourceFailureException(
"Failed to open SQL script '"
+ sqlResourcePath +
"'."
, ex);
}
}
1.
可以子类方便使用日志工具。
/**
Logger
available
to
subclasses
*/
protected
final
Log
logger
= LogFactory.getLog(getClass())
1. Timer和Quartz之间区别TimerTasks are shared instances, in contrast to throwaway Quartz Jobs.
5.9.1 配置方式
1. 分散配置。对于不同功能的配置文件分开管理
2.
建议业务相关的配置信息,都统一配置到一个配置文件中,而不要保存到库中,本身访问库是比较耗时的操作。
3.
对于初始化数据的配置,建议做成初始化脚本的形式,插入到
DB
中。
5.9.2 内存DB配置
<!-- in-memory datasource, for demo purposes only of course -->
<
bean
id
=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method
=
"close"
>
<
property
name
=
"url"
value
=
"jdbc:hsqldb:mem:carplant"
/>
<
property
name
=
"username"
value
=
"sa"
/>
<
property
name
=
"password"
value
=
""
/>
<
property
name
=
"driverClassName"
value
=
"org.hsqldb.jdbcDriver"
/>
</
bean
>
1.所有的源代码都单元测试代码。
/**
*
A
buffered
character
-
input
stream
that
keeps
track
of
line
numbers.
*
This
class
defines
methods
<CODE>
void
setLineNumber(int)
</CODE>
and
*
<CODE>
int
getLineNumber()
</CODE>
for
setting
and
getting
the
current
*
line
number
respectively.
*
<P>
*
By
default,
line
numbering
begins
at
0.
This
number
increments
as
data
is
*
read,
and
can
be
changed
with
a
call
to
<CODE>
setLineNumber(int)
</CODE>
.
*
Note
however,
that
<CODE>
setLineNumber(int)
</CODE>
does
not
actually
change
the
current
*
position
in
the
stream;
it
only
changes
the
value
that
will
be
returned
*
by
<CODE>
getLineNumber()
</CODE>
.
*
<P>
*
A
line
is
considered
to
be
terminated
by
any
one
of
a
line
feed
('/n'),
a
carriage
*
return
('/r'),
or
a
carriage
return
followed
immediately
by
a
linefeed.
ResourceUtils
一些帮助方法
*
Strategy
interface
for
loading
resources
(e..
class
path
or
file
system
*
resources).
An
{@link org.springframework.context.ApplicationContext}
*
is
required
to
provide
this
functionality,
plus
extended
*
{@link org.springframework.core.io.support.ResourcePatternResolver}
support.
*
Enumeration
that
represents
transaction
propagation
behaviors
*
for
use
with
the
JDK
1.5+
transaction
annotation,
corresponding
*
to
the
TransactionDefinition
interface.
Convenience
class
for
Spring
-
aware
Struts
1.1+
Actions.
*
*
<p>
Provides
a
reference
to
the
current
Spring
application
context,
e.g.
*
for
bean
lookup
or
resource
loading.
Auto
-
detects
a
ContextLoaderPlugIn
*
context,
falling
back
to
the
root
WebApplicationContext.
For
typical
*
usage,
i.e.
accessing
middle
tier
beans,
use
a
root
WebApplicationContext.
7.5 文件上传
支持文件上传。封装commons的文件上传机制。参见:org.springframework.web.multipart.commons
7.6 接口设计
public interface WebApplicationContext extends ApplicationContext, ThemeSource {
/**
* Context attribute to bind root WebApplicationContext to on successful startup.
* <p>Note: If the startup of the root context fails, this attribute can contain
* an exception or error as value. Use WebApplicationContextUtils for convenient
* lookup of the root WebApplicationContext.
* @see org.springframework.web.context.support.WebApplicationContextUtils#getWebApplicationContext
* @see org.springframework.web.context.support.WebApplicationContextUtils#getRequiredWebApplicationContext
*/
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class + ".ROOT";
注释:这个是个名字,是个标识,对java map,来说是key
/**
* Return the standard Servlet API ServletContext for this application.
*/
ServletContext getServletContext();
设计思想: 在最高接口中要设计get方法,不要设计set方法,让具体的实现接口、或类去做set方法。
}
7.7 事件分发
ApplicationEventPublisher
7.8 Accessor的设计模式
1. MessageSourceAccessor
* Helper class for easy access to messages from a MessageSource,
* providing various overloaded getMessage methods.
*
* <p>Available from ApplicationObjectSupport, but also reusable
* as a standalone helper to delegate to in application objects.
2. HibernateAccessor
* Base class for HibernateTemplate and HibernateInterceptor, defining common
* properties like SessionFactory and flushing behavior.
*
* <p>Not intended to be used directly. See HibernateTemplate and HibernateInterceptor.
7.9 异常类和异常转换器的设计
1.异常类的设计架构是?
2.
SessionFactoryUtils 中有异常进行转换的相关函数。convertHibernateAccessException
SQLExceptionTranslator
class IllegalArgumentException extends RuntimeException
Error:
* An <code>Error</code> is a subclass of <code>Throwable</code>
* that indicates serious problems that a reasonable application
* should not try to catch. Most such errors are abnormal conditions.
* The <code>ThreadDeath</code> error, though a "normal" condition,
* is also a subclass of <code>Error</code> because most applications
* should not try to catch it.
7.10 ServletEndpointSupport
*
Convenience
base
class
for
JAX
-
RPC
servlet
endpoint
implementations.
*
Provides
a
reference
to
the
current
Spring
application
context,
*
e.g.
for
bean
lookup
or
resource
loading.
7.11 在接口中定义常量
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
*
Interface
to
provide
configuration
for
a
web
application.
This
is
read
-
only
while
*
the
application
is
running,
but
may
be
reloaded
if
the
implementation
supports
this.
7.12 Escape字符过滤工具类
HtmlUtils
WebUtils
JavascriptUtils
7.13 Constants类的设计
private static final Constants constants = new Constants(HibernateAccessor.class);
7.14 Callback机制设计
1.HibernateCallback
public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
throws DataAccessException {
return execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
if (lockMode != null) {
return session.get(entityClass, id, lockMode);
}
else {
return session.get(entityClass, id);
}
}
}, true);
}
Note:
3.
New HibernateCallback
是实现了一个这个接口的实例,在
java
的图形设计中经常用到。形成的这个实例类,它本身就实现了
doInHibernate
方法。
然后再
excute
方法中,
就可以直接的调用这个方法了。
HibernateCallback
是个接口,这样写是为了简化编程,
java
支持这样的设计方式。
4.
目的是调用
session
(
hibernate
的类)来完成一些操作。而
session
是其他系统的(
hibernate
类)。
就是一个系统调用另外一个系统或模块时,一个很好的设计方式。
5.
一般的思路是:继承这个接口,写一个实现这个接口方法的类,这是完全没有必要的,
6.
new HibernateCallback()
相当于建立了一个临时的子类,来完成相关的操作,返回相关的调用结果,有
session
来完成使命,然后脱离关系。
/**
* Execute the action specified by the given action object within a Session.
* @param action callback object that specifies the Hibernate action
* @param exposeNativeSession whether to expose the native Hibernate Session
* to callback code
* @return a result object returned by the action, or <code>null</code>
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
*/
public Object execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
// 它是把get/load/flush/clear等等,进行了高层抽象,
// 用汉语描述: 1、调用spring的get 2、然后创建HibernateCallback接口的实例// 3、开始执行execute方法。 先获得session ,然后,调用 HibernateCallback接口的实例的实现方法。
这个流程完成。
Session session = getSession();
boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
Object result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
}
catch (RuntimeException ex) {
// Callback code threw application exception...
throw ex;
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
}
2.
7.15 Transient关键字的使用
在SessionImpl类中的属性
private transient SessionFactoryImpl factory;
7.16 WebApplicationContextUtils
public
abstract
class
WebApplicationContextUtils
工具类,不可以实例化。一种很好设计模式。不用再写成单态的类。
*
Convenience
methods
to
retrieve
the
root
WebApplicationContext
for
a
given
*
ServletContext.
This
is
e.g.
useful
for
accessing
a
Spring
context
from
*
within
custom
web
views
or
Struts
actions.
7.17 AbstractRefreshableWebApplicationContext
This
is
the
web
context
to
be
subclassed
for
a
different
bean
definition
format.
</b>
*
Such
a
context
implementation
can
be
specified
as
"contextClass"
context
-
param
*
for
ContextLoader
or
"contextClass"
init
-
param
for
FrameworkServlet,
replacing
*
the
default
XmlWebApplicationContext.
It
would
automatically
receive
the
*
"contextConfigLocation"
context
-
param
or
init
-
param,
respectively.
7.18 异常转换
SessionFactoryUtils中的convertHibernateAccessException提供了很多转换的方法。
HibernateAccessor
7.19 Filter
AbstractRequestLoggingFilter
CharacterEncodingFilter
这些过滤器,可以直接使用。
实现接口的逻辑步骤。在effective java中,有详细的解释。
*
Base
class
for
<code>
Filter
</code>
s
that
perform
logging
operations
before
and
after
a
*
request
is
processed.
7.20 Aware设计模式
1
.
ServletContextAware
Interface
to
be
implemented
by
any
object
that
wishes
to
be
notified
*
of
the
ServletContext
(typically
determined
by
the
WebApplicationContext)
*
that
it
runs
in.
7.21 ContextLoaderServlet
*
Bootstrap
servlet
to
start
up
Spring's
root
WebApplicationContext.
*
Simply
delegates
to
ContextLoader.
ContextLoader:
*
Performs
the
actual
initialization
work
for
the
root
application
context.
*
Called
by
ContextLoaderListener
and
ContextLoaderServlet.
*
*
<p>
Looks
for
a
"contextClass"
parameter
at
the
web.xml
context
-
param
level
*
to
specify
the
context
class
type,
falling
back
to
the
default
of
*
{@link XmlWebApplicationContext}
if
not
found.
With
the
default
ContextLoader
*
implementation,
any
context
class
specified
needs
to
implement
*
ConfigurableWebApplicationContext.
7.21.1 在web.xml中的配置
<
servlet-name
>
context
</
servlet-name
>
<
servlet-class
>
org.springframework.web.context.ContextLoaderServlet
</
servlet-class
>
<
load-on-startup
>
1
</
load-on-startup
>
</
servlet
>
7.21.2 实际调用分析
ContextLoader 是个代理类,它来完成实际的逻辑程序。
Performs
the
actual
initialization
work
for
the
root
application
context.
l
Called
by
ContextLoaderListener
and
ContextLoaderServlet.
有几个类,相互协作进行完成。他将进行的解析
web.xml
配置文件。
7.22 类中static的使用
在程序启动时,已经被初始化,当调用时,可以节省时间。
static
{
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try
{
ClassPathResource resource =
new
ClassPathResource(
DEFAULT_STRATEGIES_PATH
, ContextLoader.
class
);
defaultStrategies
= PropertiesLoaderUtils.loadProperties(resource);
}
catch
(IOException ex) {
throw
new
IllegalStateException(
"Could not load 'ContextLoader.properties': "
+ ex.getMessage());
}
}
7.23 SystemPropertyUtils
Helper class for resolving placeholders in texts. Usually applied to file paths.
7.24 获得客户端IP方法
private String getClientIp() {
MessageContext mc = MessageContext.getCurrentContext();
HttpServletRequest request = (HttpServletRequest) mc
.getProperty(HTTPConstants.MC_HTTP_SERVLETREQUEST);
logger.debug(" == clientIp is : " + request.getRemoteAddr());
return request.getRemoteAddr();
}
7.25 Listener的设计
<
listener
>
<
listener-class
>
org.springframework.web.util.WebAppRootListener
</
listener-class
>
</
listener
>
<
listener
>
<
listener-class
>
org.springframework.web.util.Log4jConfigListener
</
listener-class
>
</
listener
>
<
listener
>
<
listener-class
>
org.springframework.web.context.ContextLoaderListener
</
listener-class
>
</
listener
>
1. 顺序不能替换。
2. ContextLoaderServlet 中有详细的描述。
3.
注意
web.xml
文件的配置是有顺序的。参见:
web-app_2_3.dtd
4.
7.26 Assert类的设计
Assert提供了判断传入参数的很多好的方法。
8.1 Exception处理
convertHibernateAccessException
简化了书写方式。
convertJdbcAccessException
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
Object result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
return result;
}
catch (HibernateException ex) {
throw convertHibernateAccessException(ex);
}
catch (SQLException ex) {
throw convertJdbcAccessException(ex);
}
catch (RuntimeException ex) {
// Callback code threw application exception...
throw ex;
}
finally {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
if (previousFlushMode != null) {
session.setFlushMode(previousFlushMode);
}
}
else {
SessionFactoryUtils.releaseSession(session, getSessionFactory());
}
}
9 定时器配置
参见:spring
自带的sample
目录,有具体实例。
9.1 调度任务的配置MethodInvokingJobDetailFactoryBean
看这个类,能有几个属性需要配置时,可以看它的源代码,
MethodInvokingJobDetailFactoryBean
、 MethodInvoker
,定义了相关的参数属性。
<bean id="SignOrderTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="signOrder" />
<property name="startDelay">
<value>60000</value><!-- 服务启动一分钟后执行 -->
</property>
<property name="repeatInterval">
<value>45000</value>
</property>
</bean>
<bean id="signOrder" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="worker1"/>
<property name="targetMethod" value="checkCountMoney"/>
<property name="arguments"> <!-- 定义参数 -->
<list>
<value>AddSignOrder</value>
<null/>
<null/>
</list>
</property>
<property name="concurrent" value="false"/>
<property name="jobDetail" ref="signOrder" />
<property name="startDelay">
<value>60000</value><!-- 服务启动一分钟后执行 -->
</property>
<property name="repeatInterval">
<value>45000</value>
</property>
</bean>
<bean id="signOrder" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="worker1"/>
<property name="targetMethod" value="checkCountMoney"/>
<property name="arguments"> <!-- 定义参数 -->
<list>
<value>AddSignOrder</value>
<null/>
<null/>
</list>
</property>
<property name="concurrent" value="false"/>
1. <!-- 设并发为FALSE ,这样会一个接一个走-->
</bean>
</bean>
10 工具类
HtmlUtils
JavascriptUtil
SessionFactoryUtils
提供了很多对class
操作。
1
.public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
logger.debug("Cannot access thread context ClassLoader - falling back to system class loader", ex);
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
}
return cl;
}
10.2 WebUtils
Miscellaneous utilities for web applications.Used by various framework classes.
11 配置文件
11.1 配置log4j
Log4jConfigServlet
Log4jWebConfigurer
全面的包装
在
web.xml
中加入以下代码即可。
<
context-param
>
< param-name > log4jConfigLocation < /param-name > < param-value > /WEB-INF/log4j.properties < /param-value > < /context-param > |
11.2 Web.xml配置jndi
如果使用Jndi
访问数据库,
<!--
- Reference to PetClinic database.
- Only needed if not using a local DataSource but a JNDI one instead.
-->
<!--
<resource-ref>
<res-ref-name>jdbc/petclinic</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
-->
11.3 几种数据源配置
<!--
Simple local DataSource that works in any environment.
This uses the JDBC DriverManager to obtain connections, and does NOT perform connection
pooling. Connection pooling is essential to all real-world applications.
This definition is good for getting started, as it introduces no dependencies beyond
the JDK, but DriverManagerDataSource is not intended for production usage.
-->
<
bean
id
=
"dataSource"
class
=
"org.springframework.jdbc.datasource.DriverManagerDataSource"
>
<
property
name
=
"driverClassName"
value
=
"${jdbc.driverClassName}"
/>
<
property
name
=
"url"
value
=
"${jdbc.url}"
/>
<
property
name
=
"username"
value
=
"${jdbc.username}"
/>
<
property
name
=
"password"
value
=
"${jdbc.password}"
/>
</
bean
>
<!--
Alternative local DataSource that works in any environment, and offers much better performance.
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
for the required JAR files. See the PetStore sample application also shipped with
Spring, for an example of Commons DBCP usage and the necessary build script.
Alternatively you can use another connection pool such as C3P0, similarly configured
using Spring.
A standalone connection pool such as Commons DBCP is a good choice for use outside an
application server environment, including web applications running in a web container without
JTA, or integration testing using the org.springframework.test package.
-->
<!--
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
-->
<!-- JNDI DataSource for J2EE environments -->
<!--
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/petclinic"/>
</bean>
-->
12 数据库分页
13 参考资料