Spring开发风格_thunder4393的专栏-CSDN博客
1 前言
本文档是关于Spring框架开发风格分析性文档。包括:基本概念、设计原则、设计规范、重要功能分析、关键类分析等。
本文档适合所有Java开发人员。
2 概念
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
3 代码准则
1.功能类和工具类分离的原则。
4 设计规范
4.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 包。存在异常类,对于所有可能的异常,根据分类,都可以单独进行命名。
4.2 类
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.
4.3 属性
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
4.4 方法
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
4.5 常量
1.Enum方式。例如: propagation
2.工具类可以定义常量。WebUtils
4.6 异常
1. 对于catch到的所有异常,对于实例都可以命名为:ex
catch (MailException ex) {
throw ex;
}
2. 异常的命名 完全描述操作的意图CannotGetJdbcConnectionException 、 NameNotFoundException
4.7 工具类
1. 提供一些计算、查询、统计等工具性方法。
2. 可以广泛的被其他类进行引用。
3. 验证参数类,Spring有自己的Validator 和Errors相互配合使用
4. 通常以utils结尾。例如:ValidationUtils、WebApplicationContextUtils
5.
4.8 注释
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
4.9 常用英文注释和单词
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 指定的
4.10 其他
1.
5 设计方式
5.1 类文件分析
LocalVariableTableParameterNameDiscoverer
ParameterNameDiscoverer
Uses ObjectWeb's ASM library for analyzing class files.
5.2 类委托
DelegatingActionUtils
5.3 函数委托
/**
* 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;
}
5.4 继承
1.通常为接口提供了一些默认实现、通用实现。每一个类都有自己的责任。
a) ContextLoader
b) AbstractContextLoader
c) AbstractGenericContextLoader
2.
5.5 向JVM注册回调
AbstractApplicationContext.registerShutdownHook
Register a shutdown hook with the JVM runtime,
5.6 异常后,继续执行
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);
}
}
5.7 日志代码
1. 可以子类方便使用日志工具。
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass())
5.8 定时设计
1. Timer和Quartz之间区别TimerTasks are shared instances, in contrast to throwaway Quartz Jobs.
5.9 配置
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 >
6 测试
1.所有的源代码都单元测试代码。
7 类分析
7.1 LineNumberReader
/**
* 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.
7.2 ResourceLoader
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.
7.3 Propagation
* Enumeration that represents transaction propagation behaviors
* for use with the JDK 1.5+ transaction annotation, corresponding
* to the TransactionDefinition interface.
7.4 ActionSupport
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 异常处理
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"/>
1. <!-- 设并发为FALSE ,这样会一个接一个走-->
</bean>
10 工具类
HtmlUtils
JavascriptUtil
SessionFactoryUtils
10.1 ClassUtils
提供了很多对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 参考资料
————————————————
版权声明:本文为CSDN博主「thunder4393」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/thunder4393/article/details/1912455