JdbcTemplate在 spring-jdbc-5.0.2.RELEASE.jar 中,在导包的时候,除了要导入这个 jar 包 外,还需要导入一个 spring-tx-5.0.2.RELEASE.jar(它是和事务相关的)。
**作用:**用于和数据库交互,实现对表的CRUD操作
可以参考它的源码,来查看:
public JdbcTemplate() {
}
public JdbcTemplate(DataSource dataSource) {
setDataSource(dataSource);
afterPropertiesSet();
}
public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
setDataSource(dataSource);
setLazyInit(lazyInit);
afterPropertiesSet();
}
除了默认构造函数之外,其它两个都需要提供一个数据源。既然有set方法,依据之前的依赖注入,可以在配置文件中配置这些对象。
创建一个maven工程
pom.xml文件导入需要的依赖
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
创建账户的实体类:
package com.xsh.domain;
import java.io.Serializable;
/**
* 账户的实体类
*/
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
//此处已省略getter,setter,toString方法...
}
此处使用spring的内置数据源DriverManagerDataSource,其它数据源还有C3P0, DBCP等
package com.xsh.jdbctemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
/**
* JdbcTemplate的最基本用法
*/
public class JdbcTemplateDemo1 {
public static void main(String[] args) {
//准备数据源:spring的内置数据源DriverManagerDataSource
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("123456");
//1.创建JdbcTemplate对象
JdbcTemplate jt = new JdbcTemplate();
//2.给jt设置数据源
jt.setDataSource(ds);
//3.执行操作
jt.execute("insert into account(name,money)values('ccc',1000)");
}
}
定义属性文件
在resources目录下新建jdbc.properties文件:
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///test
jdbc.username=root
jdbc.password=123456
引入外部的属性文件
方式一:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
方式二:
<context:property-placeholder location="classpath:jdbc.properties"/>
如果用注解配置,使用方法一:
IAccountDao:
package com.xsh.dao;
import com.xsh.domain.Account;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 根据Id查询账户
*/
Account findAccountById(Integer accountId);
/**
* 根据名称查询账户
*/
Account findAccountByName(String accountName);
/**
* 更新账户
*/
void updateAccount(Account account);
}
AccountDaoImpl:
package com.xsh.dao.impl;
import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import java.util.List;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = jdbcTemplate.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts =jdbcTemplate.query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("结果集不唯一");
}
return accounts.get(0);
}
@Override
public void updateAccount(Account account) {
jdbcTemplate.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
配置bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://http://cdn.xiongsihao.com.springframework.org/schema/beans
http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置账户的持久层-->
<bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
测试查看结果:
package com.xsh.jdbctemplate;
import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JdbcTemplateDemo4 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
IAccountDao accountDao = ac.getBean("accountDao",IAccountDao.class);
Account account = accountDao.findAccountById(1);
System.out.println(account);
account.setMoney(30000f);
accountDao.updateAccount(account);
}
}
当使用xml配置,使用方法二,因为JdbcDaoSupport是jar包中的类,jar包中的JdbcTemplate无法使用@Autowired注解,因为jar包中的内容是只读的无法被修改:
因为在方法一中,当dao 有很多时,每个 dao 都有一些重复性的代码。下面就是重复代码:
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
所以可以通过继承JdbcDaoSupport来去除注入setJdbcTemplate的重复代码:
修改bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://http://cdn.xiongsihao.com.springframework.org/schema/beans
http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置账户的持久层-->
<bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--去除注入JdbcTemplate,直接注入dataSource,因为JdbcDaoSupport已经帮我们实现了JdbcTemplate的创建-->
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
</beans>
AccountDaoImpl:继承JdbcDaoSupport, 使用super.getJdbcTemplate( )执行sql语句
package com.xsh.dao.impl;
import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import java.util.List;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
@Override
public Account findAccountById(Integer accountId) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),accountId);
return accounts.isEmpty()?null:accounts.get(0);
}
@Override
public Account findAccountByName(String accountName) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where name = ?",new BeanPropertyRowMapper<Account>(Account.class),accountName);
if(accounts.isEmpty()){
return null;
}
if(accounts.size()>1){
throw new RuntimeException("结果集不唯一");
}
return accounts.get(0);
}
@Override
public void updateAccount(Account account) {
super.getJdbcTemplate().update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
}
}
package com.xsh.jdbctemplate;
import com.xsh.domain.Account;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* JdbcTemplate的CRUD操作
*/
public class JdbcTemplateDemo3 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
//保存
// jt.update("insert into account(name,money)values(?,?)","eee",3333f);
//更新
// jt.update("update account set name=?,money=? where id=?","test",4567,7);
//删除
// jt.update("delete from account where id=?",8);
//查询所有
// List<Account> accounts = jt.query("select * from account where money > ?",new AccountRowMapper(),1000f);
// List<Account> accounts = jt.query("select * from account where money > ?",new BeanPropertyRowMapper<Account>(Account.class),1000f);
// for(Account account : accounts){
// System.out.println(account);
// }
//查询一个
// List<Account> accounts = jt.query("select * from account where id = ?",new BeanPropertyRowMapper<Account>(Account.class),1);
// System.out.println(accounts.isEmpty()?"没有内容":accounts.get(0));
//查询返回一行一列(使用聚合函数,但不加group by子句)
Long count = jt.queryForObject("select count(*) from account where money > ?",Long.class,1000f);
System.out.println(count);
}
}
/**
* 自定义Account的封装策略,相当于spring提供的BeanPropertyRowMapper
*/
class AccountRowMapper implements RowMapper<Account>{
/**
* 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
* @param rs
* @param rowNum
* @return
* @throws SQLException
*/
@Override
public Account mapRow(ResultSet rs, int rowNum) throws SQLException {
Account account = new Account();
account.setId(rs.getInt("id"));
account.setName(rs.getString("name"));
account.setMoney(rs.getFloat("money"));
return account;
}
}
JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计 业务层的事务处理解决方 案。
spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我 们学习的重点是使用配置的方式实现。
spring 框架为我们提供了一组事务控制的接口。这组接口是在spring-tx-5.0.2.RELEASE.jar 中。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
Spring所有事务代理类都是基于PlatformTransactionManager接口的实现。
此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法:
//获得事务信息
TransactionStatus getTransaction(TransactionDefinition definition)
//提交事务
void commit(TransactionStatus status)
//回滚事务
void rollback(TransactionStatus status)
在实际开发中都是使用它的实现类,如下:
//用于Spring JDBC以及Mybatis框架的事务代理
DataSourceTransactionManager
//用于Hibernate框架事务代理
HibernateTransactionManager
//用于Jpa框架的事务代理
JpaTransactionManager
//用于JDO框架的事务代码
JdoTransactionManager
//用于Jta事务代理,一个事务跨多资源必须要使用
JtaTransactionManager
TransactionDefinition
接口是用于定义一个事务,它定义了Spring事务管理的五大属性
源码,有以下方法:
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();//事务的传播行为
int getIsolationLevel();//事务的隔离级别
int getTimeout();//事务超时时间
boolean isReadOnly();//是否只读
String getName();//获取事物对象名称
}
事务的传播行为:
超时时间:默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
是否是只读事务:建议查询时设置为只读。
TransactionStatus
接口代表了一个事务本身,提供了一个简单的控制事务执行和查询事务状态的方法。PlatformTransactionManager
接口的getTransaction()方法会返回一个TransactionStatus
对象,该对象可能代表一个新的或者一个已经存在的事务。
TransactionStatus
接口源码如下:
public interface TransactionStatus extends SavepointManager, Flushable {
boolean isNewTransaction();//是否一个新的事务
boolean hasSavepoint();//
void setRollbackOnly();//将事务设置为只能回滚,不允许提交
boolean isRollbackOnly();//查询事务是否已有回滚标志
void flush();//刷新事物
boolean isCompleted();//查询事务是否结束
}
修改转账案例的bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://http://cdn.xiongsihao.com.springframework.org/schema/aop"
xmlns:tx="http://http://cdn.xiongsihao.com.springframework.org/schema/tx"
xsi:schemaLocation="
http://http://cdn.xiongsihao.com.springframework.org/schema/beans
http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd
http://http://cdn.xiongsihao.com.springframework.org/schema/tx
http://http://cdn.xiongsihao.com.springframework.org/schema/tx/spring-tx.xsd
http://http://cdn.xiongsihao.com.springframework.org/schema/aop
http://http://cdn.xiongsihao.com.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置业务层-->
<bean id="accountService" class="com.xsh.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置账户的持久层-->
<bean id="accountDao" class="com.xsh.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- spring中基于XML的声明式事务控制配置步骤
1、配置事务管理器
2、配置事务的通知
此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用
3、配置AOP中的通用切入点表达式
4、建立事务通知和切入点表达式的对应关系
5、配置事务的属性
是在事务的通知tx:advice标签的内部
-->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 配置aop-->
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.xsh.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入点表达式和事务通知的对应关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>
AccountServiceImpl:
package com.xsh.service.impl;
import com.xsh.dao.IAccountDao;
import com.xsh.domain.Account;
import com.xsh.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* 账户的业务层实现类
*
* 事务控制应该都是在业务层
*/
@Service("accountService")
@Transactional(propagation= Propagation.SUPPORTS,readOnly=true)//只读型事务的配置
public class AccountServiceImpl implements IAccountService{
@Autowired
private IAccountDao accountDao;
@Override
public Account findAccountById(Integer accountId) {
return accountDao.findAccountById(accountId);
}
//需要的是读写型事务配置
@Transactional(propagation= Propagation.REQUIRED,readOnly=false)
@Override
public void transfer(String sourceName, String targetName, Float money) {
System.out.println("transfer....");
//2.1根据名称查询转出账户
Account source = accountDao.findAccountByName(sourceName);
//2.2根据名称查询转入账户
Account target = accountDao.findAccountByName(targetName);
//2.3转出账户减钱
source.setMoney(source.getMoney()-money);
//2.4转入账户加钱
target.setMoney(target.getMoney()+money);
//2.5更新转出账户
accountDao.updateAccount(source);
int i=1/0;
//2.6更新转入账户
accountDao.updateAccount(target);
}
}
bean.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://http://cdn.xiongsihao.com.springframework.org/schema/beans"
xmlns:xsi="http://http://cdn.xiongsihao.com.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://http://cdn.xiongsihao.com.springframework.org/schema/aop"
xmlns:tx="http://http://cdn.xiongsihao.com.springframework.org/schema/tx"
xmlns:context="http://http://cdn.xiongsihao.com.springframework.org/schema/context"
xsi:schemaLocation="
http://http://cdn.xiongsihao.com.springframework.org/schema/beans
http://http://cdn.xiongsihao.com.springframework.org/schema/beans/spring-beans.xsd
http://http://cdn.xiongsihao.com.springframework.org/schema/tx
http://http://cdn.xiongsihao.com.springframework.org/schema/tx/spring-tx.xsd
http://http://cdn.xiongsihao.com.springframework.org/schema/aop
http://http://cdn.xiongsihao.com.springframework.org/schema/aop/spring-aop.xsd
http://http://cdn.xiongsihao.com.springframework.org/schema/context
http://http://cdn.xiongsihao.com.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.xsh"></context:component-scan>
<!-- 配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!-- spring中基于注解 的声明式事务控制配置步骤
1、配置事务管理器
2、开启spring对注解事务的支持
3、在需要事务支持的地方使用@Transactional注解
-->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启spring对注解事务的支持-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
spring5.0 在 2017 年 9 月发布了它的 GA(通用)版本。该版本是基于 jdk8 编写的,所以 jdk8 以下版本 将无法使用。同时,可以兼容 jdk9 版本。
package com.xsh.test;
import java.lang.reflect.Method;
public class Test {
//循环次数定义:10亿次
private static final int loopCnt = 1000 * 1000 * 1000;
public static void main(String[] args) throws Exception {
//输出jdk的版本
System.out.println("java.version=" + System.getProperty("java.version"));
t1();
t2();
t3();
}
// 每次重新生成对象
public static void t1() {
long s = System.currentTimeMillis();
for (int i = 0; i < loopCnt; i++) {
Person p = new Person();
p.setAge(31);
}
long e = System.currentTimeMillis();
System.out.println("循环10亿次创建对象的时间:" + (e - s));
}
// 同一个对象
public static void t2() {
long s = System.currentTimeMillis();
Person p = new Person();
for (int i = 0; i < loopCnt; i++) {
p.setAge(32);
}
long e = System.currentTimeMillis();
System.out.println("循环10亿次给同一对象赋值的时间: " + (e - s));
}
//使用反射创建对象
public static void t3() throws Exception {
long s = System.currentTimeMillis();
Class<Person> c = Person.class;
Person p = c.newInstance();
Method m = c.getMethod("setAge", Integer.class);
for (int i = 0; i < loopCnt; i++) {
m.invoke(p, 33);
}
long e = System.currentTimeMillis();
System.out.println("循环10亿次反射创建对象的时间:" + (e - s));
}
static class Person {
private int age = 20;
public int getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
}
运行结果:
java.version=1.7.0_72 循环10亿次创建对象的时间:6212 循环10亿次给同一对象赋值的时间: 3025 循环10亿次反射创建对象的时间:290400
java.version=1.8.0_101 循环10亿次创建对象的时间:20 循环10亿次给同一对象赋值的时间: 150 循环10亿次反射创建对象的时间:3759
可以对比发现,对于jdk1.8,反射创建对象时间大大缩减
用 @Nullable 和 @NotNull 注解来显示表明可为空的参数和以及返回值。这样就够在编译的时候处 理空值而不是在运行时抛出 NullPointerExceptions。
Spring Framework 5.0 带来了 Commons Logging 桥接模块的封装, 它被叫做 spring-jcl 而 不是标准的 Commons Logging。当然,无需任何额外的桥接,新版本也会对 Log4j 2.x, SLF4J, JUL ( java.util.logging) 进行自动检测。
评论