Spring实战笔记 1

来源:互联网 发布:厦门大学网络教育本科 编辑:程序博客网 时间:2024/06/15 04:02
虽然Spring用bean或者JavaBean来表示应用组件,但并不意味着Spring组件必须要遵循JavaBean规范。一个Spring组件可以是任何形式的POJO。


三个主要内容:依赖注入,切面,模板代码

<beans><aop:config><aop:aspect ref="minstrel"><aop:pointcut id="embark" expression="execution(* *.embarkOnQuest(...))" /><aop:before pointcut-ref="embark" method="singBeforeQuest" /><aop:after pointcut-ref="embark" method="singAfterQuest"></aop:aspect></aop:config></beans>


表达式的语法采用的是AspectJ的切点表达式语言。


public Employee getEmployeeById(long id){return jdbcTemplate.queryForObject("select id, firstname, lastname, salary from employee where id=?",new RowMapper<Employee>(){public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {Employee employee = new Employee();employee.setId(rs.getLong("id"));employee.setFirstName(rs.getString("firstname"));employee.setLastName(rs.getString("lastname"));employee.setSalary(rs.getBigDecimal("salary"));return employee;}})}



常用的应用上下文:
AnnotationConfigApplicationContext
AnnotationConfigWebApplicationContext
ClassPathXmlApplicationContext
FileSystemXmlApplicationContext
XmlWebApplicationContext


Bean的生存周期:
实例化 => 填充属性 => BeanNameAware => BeanFactoryAware => ApplicationContextAware
 => BeanPostProcessor的预初始化方法 => InitializingBean的afterPropertiesSet方法 => 调用自定义初始化方法 => 调用BeanPostProcessor的初始化后方法
 => Bean可以使用了
 => 调用DisposableBean的destroy()方法 => 调用自定义销毁方法


 Spring框架的模块分类:
1. Spring核心容器: Beans, Core, Context, Expression, Context support
2. 面向切面编程: AOP, Aspects
3. 数据访问与集成:JDBC, Transaction, ORM, OXM, Messaging, JMS
4. Web与远程调用:Web, Web servlet, Web portlet, WebSocket
5. Instrumentation: Instrument, Instrument Tomcat
6. Test


Spring提供了三种主要的装配机制:
1. 在XML中进行显式配置
2. 在Java中进行显式配置
3. 隐式的bean发现机制和自动装配。


自动发现:
@Configuration
@ComponentScan
public class CDPlayerConfig{
}
按照默认规则,它会以配置类所在的包作为基础包来扫描组件。
@ComponentScan("soundsystem")
@ComponentScan(basePackages={"soundsystem", "video"})
@ComponentScan(basePackageClasses={CDPlayer.class, DVDPlayer.class})



@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=CDPlayerConfig.class)public class CDPlayerTest{@Testpublic void fn(){System.out.println(1);}}




profile bean。
Spring为环境相关的bean所提供的解决方案其实与构建时的方案没有太大的差别。当然,在这个过程中需要根据环境决定该创建哪个bean和不创建哪个bean。不过Spring并不是在构建的时候做出这样的决策,而是等到运行时再来确定。这样的结果就是同一个部署单元(可能会是WAR文件)能够适用于所有的环境,没有必要进行重新构建。
Spring在确定哪个profile处于激活状态时,需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default。
有多种方式来设置这两个属性:
作为DispatcherServlet的初始化参数。
作为Web应用的上下文参数
作为JNDI条目
作为环境变量
作为JVM的系统属性
在集成测试类上,使用@ActiveProfiles注解设置。


Spring定义了多种作用域,可以基于这些作用域创建bean,包括:
1. 单例(Singleton):在整个应用中,只创建bean的一个实例。
2. 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
3. 会话(Session):在Web应用中,为每个会话创建一个bean实例。
4. 请求(Request):在Web应用中,为每个请求创建一个bean实例。


@Component@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)public ShoppingCart cart(){ ... }


proxyMode这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。


在@Configuration类上可以指定@PropertySource注解来指定属性来源,之后就可以注入Environment来调用它的getProperty方法获取属性性。


Spring切面可以应用5种类型的通知:
1. 前置通知
2. 后置通知
3. 返回通知
4. 异常通知
5. 环绕通知








第10章


在开发应用的持久层的时候,会面临多种选择,我们可以使用JDBC、Hibernate、Java持久化API(JPA)或者其他任意的持久化框架。


为了避免持久化的逻辑分散到应用的各个组件中,最好将数据访问的功能放到一个或多个专注于此项任务的组件中。这样的组件通常称为数据访问对象(DAO)或Repository。
为了避免应用与特定的数据访问策略耦合在一起,编写良好的Repository应该以接口的方式暴露功能。
如果在阅读了上面几段文字之后,你能感受到我倾向于将持久层隐藏在接口之后,那很高兴我的目的达到了。我相信接口是实现松耦合代码的关键,并且应将其用于应用程序的各个层,而不仅仅是持久化层。


Spring提供与平台无关的持久化异常,这意味着我们可以使用Spring抛出一致的异常,而不用关心所选择的持久化方案。
这些异常都继承自DataAccessException,DataAccessException的特殊之处在于它是一个非检查型异常。换句话说,没有必要捕获Spring所抛出的数据访问异常(当然,如果你想捕获的话也是完全可以的)。


配置数据源的三种方式:
1. 通过JDBC驱动程序定义的数据源。
2. 通过JNDI查找的数据源。
3. 连接池的数据源。
对于即将发布到生产环境中的应用程序,我建议使用从连接池获取连接的数据源。如果可能的话,我倾向于通过应用服务器的JNDI来获取数据源。


1.在Spring中,通过JDBC驱动定义数据源是最简单的配置方式。Spring提供了三个这样的数据源类:
DriverManagerDataSource:在每个连接请求时都会返回一个新建的连接
SimpleDriverDataSource:与DriverManagerDataSource的工作方式类似,但是它直接使用JDBC驱动,来解决在特定环境下的类加载问题。
SingleConnectionDataSource:在每个连接请求时都会返回同一个连接。


2.通过JNDI查找数据源。
利用Spring,我们可以像使用Spring bean那样配置JNDI中数据源的引用并将其装配到需要的类中。
<jee:jndi-lookup id="dataSource" jndi-name="/jdbc/SpitterDSxx" resource-ref="true">




3.如果你不能从JNDI中查找数据源,那么下一个选择就是直接在Spring中配置数据源连接池。尽管Spring并没有提供数据源连接池的实现,但是我们有多项可用的方案,包括如下开源的实现:
Apache Commons DBCP
c3p0
BoneCP
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="org.h2.Driver" p:url="jdbc:h2:tcp://localhost/~/spitter" p:username="sa" p:password="" p:initialSize="5" p:maxActive="10" />@Beanpublic BasicDataSource dataSource(){BasicDataSource ds = new BasicDataSource();ds.setDriverClassName("org.h2.Driver");ds.setUrl("jdbc:h2:tcp://localhost/~/spitter");ds.setUsername("sa");ds.setPassword("");ds.setInitialSize(5);ds.setMaxActive(10);return ds;}嵌入式的数据源<jdbc:embedded-database id="dataSource" type="H2"><jdbc:script location="com/habuma/spitter/db/jdbc/schema.sql" /><jdbc:script location="com/habuma/spitter/db/jdbc/test-data.sql" /></jdbc:embedded-database>@Beanpublic DataSource dataSource(){return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:schema.sql").addScript("classpath:test-data.sql").build();}Connection conn = dataSource.getConnection();PreparedStatement stmt = conn.prepareStatement(SQL_SELECT_SPITTER);stmt.setLong(1, id)ResultSet rs = stmt.executeQuery();



Spring为JDBC提供的模板类:JdbcTemplate和NamedParameterJdbcTemplate。


配置JdbcTemplate bean:@Beanpublic JdbcTemplate jdbcTemplate(DataSource dataSource){return new JdbcTemplate(dataSource);}使用:@Repositorypublic class JdbcSpitterRepository implements SpitterRepository{private JdbcOperations jdbcOperations;@Injectpublic JdbcSpitterRepository(JdbcOperations jdbcOperations) {this.jdbcOperations = jdbcOperations;}}


在这里,JdbcSpitterRepository类上使用了@Repository注解,这表明它将会在组件扫描的时候自动创建。它的构造器上使用了@Inject注解,因此在创建的时候,会自动获得一个JdbcOperations对象。JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作。
public void addSpitter(Spitter spitter){jdbcOperations.update(INSERT_SPITTER,spitter.getUsername(),spitter.getPassword(),spitter.getFullName(),spitter.getEmail(),spitter.isUpdateByEmail());}public Spitter findOne(long id) {return jdbcOperations.queryForObject(SELECT_SPITTER_BY_ID,(rs, rowNum) -> {return new Spitter(xxx);}, id);}或用方法引用public Spitter findOne(long id) {return jdbcOperations.queryForObject(SELECT_SPITTER_BY_ID, this::mapSpitter, id);}public Spitter mapSpitter(ResultSet rs, int row) throws SQLException{xxx}




Hibernate是在开发者社区很流行的开源持久化框架。它不仅提供了基本的对象关系映射,还提供了ORM工具所应具有的所有复杂功能,比如缓存、延迟加载、预先抓取以及分布式缓存。


使用Hibernate所需的主要接口是org.hibernate.Session。Session接口提供了基本的数据访问功能,如保存、更新、删除以及从数据库加载对象的功能。通过Hibernate的Session接口,应用程序的Repository能够满足所有的持久化需求。
获取Hibernate Session对象的标准方式是借助于Hibernate SessionFactory接口的实现类。除了一些基他的任务,SessionFactory主要负责Hibernate Session的打开、关闭以及管理。
@Beanpublic LocalSessionFactoryBean sessionFactory(DataSource ds) {LocalSessionFactoryBean sfb = new LocalSessionFactoryBean();sfb.setDataSource(ds);sfb.setPackagesToScan(new String[]{"com.habuma.spittr.domain"});Properties props = new Properties();props.setProperty("dialect", "org.hibernate.dialect.H2Dialect");sfb.setHibernateProperties(props);return sfb;}




基于JPA的应用程序需要使用EntityManagerFactory的实现类来获取EntityManager实例。JPA定义了两种类型的实体管理器:应用程序管理类型,容器管理类型。
以上的两种实体管理器实现了同一个EntityManager接口。关键的区别不在于EntityManager本身,而是在于EntityManager的创建和管理方式。应用程序管理类型的EntityManager是由EntityManagerFactory创建的,而后者是通过PersistenceProvider的createEntityManagerFactory()方法得到的。与此相对,容器管理类型的EntityManagerFactory是通过PersistenceProvider的createContainerEntityManagerFactory()方法获得的。
这两种实体管理器工厂分别由对应的Spring工厂Bean创建:
LocalEntityManagerFactoryBean生成应用程序管理类型的EntityManagerFactory。
LocalContainerEntityManagerFactoryBean生成容器管理类型的EntityManagerFactory。

0 0
原创粉丝点击