- 关于 @SpringBootApplication 的主程序入口
Springboot 的程序入口类,即main方法执行的类是有一些需要注意的地方的,它的路径应当在
所有代码的根目录下。springboot 启动时是从 入口main方法所在类的目录为根目录向上扫描的。
如果main方法不在根目录则这个目录外的bean 不会被spring管理注入
2. 数据源配置
```
@Order(Ordered.HIGHEST_PRECEDENCE) ①
@Configuration ②
@EnableTransactionManagement(proxyTargetClass = true) ③
@EnableJpaRepositories(basePackages = "com.**.repository") ④
@EntityScan(basePackages = "com.**.entity") ⑤
public class JpaConfiguration {
@Bean
PersistenceAnnotationBeanPostProcessor persistenceAnnotationBeanPostProcessor() {
return new PersistenceAnnotationBeanPostProcessor();
}
}
```
① 如果有多个数据源的时候这个标记就会起作用,数据源配置的优先级
② 标明这个类是一个configuration 类,在启动时会自动读取这里的配置
③ 开启事务管理
④ 配置 repository 的路径,如果不配置的话默认应该是根目录下的repository,对于分模块的情况最好进行配置 `"com.**.repository"` 这个配置会读取所有以com开头 repository 结尾的文件。
⑤ 配置entity 的路径
多数据源的配置:
```
@Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource") ①
@Qualifier("primaryDataSource")
@ConfigurationProperties(prefix="spring.datasource.primary") ②
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@Primary ③
@ConfigurationProperties(prefix="spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(
@Qualifier("primaryDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(
@Qualifier("secondaryDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
//application.properties
spring.datasource.primary.url=jdbc:mysql://localhost:3306/adp?characterEncoding\=UTF-8
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driverClassName=com.mysql.jdbc.Driver
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/adp1?characterEncoding\=UTF-8
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root
spring.datasource.secondary.driverClassName=com.mysql.jdbc.Driver
```
① 定义一个主数据源
② 读取我们在 application.yml(properties)中的配置数据源地址信息
③ 因为我们对一个DataSourceBuiler 创造了2个实现所以 需要用@primary
多数据源同样可以配置 repository 的包路径,可以给第一个数据源配置主数据源的repository地址和 entity
同样也可以专门为第二个数据源配置专门的 repository和entity
列举一个 主数据库配置
```
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactoryPrimary",
transactionManagerRef = "transactionManagerPrimary",
basePackages = {"com"}) //设置Repository所在位置
public class PrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
@Primary
@Bean(name = "entityManagerFactoryPrimary")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(primaryDataSource)
.properties(getVendorProperties(primaryDataSource))
.packages("com") //设置实体类所在位置
.persistenceUnit("primaryPersistenceUnit")
.build();
}
@Autowired
private JpaProperties jpaProperties;
private Map<String, String> getVendorProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
}
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
```
@ComponentScan注解。这个注解的作用类似于我们在spring的xml配置文件中的base-package的作用。
在Applcation.上添加这个注解后,会自动所有子包,寻找含有@Repository、@Service、@Controller、
@Component、@RestController、@Configuration注解的类,实现实例化和依赖注入等功能。
对于一些依赖的第三方jar,由于这些类上并没有添加以上的这些注解,因此通过@ComponentScan无法直接获取其实例。
例如我们再进行Mybatis与Spring整合的使用,使用到SqlSessionFactory,通过@ComponentScan无法获取其实例。
对于这种情况, SpringBoot官方倾向于在一个添加@Configuration注解的类上,来获取需要依赖注入的Bean。
不过结合目前的Spring使用情况来说,大部分公司都是XML+注解联合使用的。
因此Spring也提供了另外一个注解@ImportResource,来导入xml格式的配置文件。所以入口类上最好加上这个注解
消失的web.xml 怎么办
通常情况下很多 filter listener 之类的都是在web.xml 中配置的,springboot 把web.xml给省掉了。
那我们想要手动加一些这样的东西该怎么办? springboot中提供了更简单的办法。
public class DemoFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("==>DemoFilter启动");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("==>DemoFilter拦截请求");
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
过滤器只需要继承 Filter 即可
import x.servlet.ServletContextEvent;
import x.servlet.ServletContextListener;
public class DemoListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("==>DemoListener启动");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
监听器也是同样的
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
@Bean
public FilterRegistrationBean getDemoFilter(){
DemoFilter demoFilter=new DemoFilter();
FilterRegistrationBean registrationBean=new FilterRegistrationBean();
registrationBean.setFilter(demoFilter);
List<String> urlPatterns=new ArrayList<String>();
urlPatterns.add("/*");//拦截路径,可以添加多个
registrationBean.setUrlPatterns(urlPatterns);
registrationBean.setOrder(1);
return registrationBean;
}
@Bean
public ServletListenerRegistrationBean<EventListener> getDemoListener(){
ServletListenerRegistrationBean<EventListener> registrationBean
=new ServletListenerRegistrationBean<>();
registrationBean.setListener(new DemoListener());
// registrationBean.setOrder(1);
return registrationBean;
}
}
最后再继承 WebMvcConfigurerAdapter 然后把这些东西加上
单元测试
建议编写一个 base类
@RunWith(SpringRunner.class) ①
@SpringBootTest ②
@Transactional ③
class base //...
① 运行环境类 ② SpringBootTest ③ 开启单元测试事务回滚
自带的定时任务
@Configuration ①
@EnableScheduling // 启用定时任务 ②
public class CustomerStatusScheduling {
private final SignRecordRepository signRecordRepository;
private final SignRecordHistoryRepository signRecordHistoryRepository;
@Autowired ③
public CustomerStatusScheduling(SignRecordRepository signRecordRepository, SignRecordHistoryRepository signRecordHistoryRepository) {
this.signRecordRepository = signRecordRepository;
this.signRecordHistoryRepository = signRecordHistoryRepository;
}
@Scheduled(cron ="0 0 0 1/1 * ?") ④
public void reSetCustomerStatus(){
signRecordRepository.reSetCustomerStatus();
}
}
① 这个标签就不用说了...
② 启动定时任务
③ 注入需要的bean (spring 高版本推荐使用这种构造器的方式来注入bean)
④ 定时任务类 在cron 写上 cron表达式即可开启定时任务
- 项目启动时自动执行方法
入口方法 实现 CommandLineRunner 接口
然后实现 它的 run 方法
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
接口源码 参数是 可变长数组String 参数
关于 spring data jpa 的一些东西
基础的 findByXXXAndXXX 的规则就不说了
分页
Pageable pageable = new PageRequest(page, num);
创建一个 Page 对象repository 接口中定义如下方法
Page findAll(Pageable pageable);
返回的PagePage源码
public interface Page<T> extends Slice<T> { int getTotalPages(); long getTotalElements(); <S> Page<S> map(Converter<? super T, ? extends S> converter); } public interface Slice<T> extends Iterable<T> { int getNumber(); int getSize(); int getNumberOfElements(); List<T> getContent(); boolean hasContent(); Sort getSort(); boolean isFirst(); boolean isLast(); boolean hasNext(); boolean hasPrevious(); Pageable nextPageable(); Pageable previousPageable(); <S> Slice<S> map(Converter<? super T, ? extends S> converter); }
page 和 slice 接口里的方法足够我们大多数分页的应用场景
获取本次分页查询数据结果 需要调用 getContent 方法 返回的是一个list的数据集
map方法是提供数据转换的方法
Spring jpa 提供了很多Coverter接口的实现findBy 关联对象
在hibernate 中经常会有 一对多 多对一的映射关系(我们系统中没这么搞)public class SignRecordHistory { @Id @GeneratedValue private Long id; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "customer") private Customer customer; @Column private Date signDate; @Column private String manager;
比如 SignRecordHistory 中有多对一映射了 customer对象
这时findBy 就需要用另一种格式来写List<SignRecordHistory> findBySignDateBetweenAndCustomer_delFlag
(Date start, Date end, int delFlag);Customer_delFlag 就表示 查找 customer.delFlag
多层结构就多个 ‘_’
springboot 依赖管理
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <kotlin.compiler.incremental>true</kotlin.compiler.incremental> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <kotlin.version>1.1.2</kotlin.version> </properties>
spring boot 配置都在 parent里
通过修改 properties 里的配置可以修改springboot 的依赖
详见 spring-boot-starter-parent-xx.pom大多数第三方jar包都是由springboot来统一管理,这样的好处是避免了各类jar包的冲突
这样做除了帮助对依赖有管理,其还有2个优点:如果之后想对依赖进行升级,只需修改spring-boot-starter-parent的版本即可,
其管理的第三方依赖即可以完成自动化的一致性升级。
帮助我们解决第三方框架由于版本不兼容而引发的冲突,稍微有点开发经验的朋友可能都有这样经历,
常常因为项目中引入了框架的JAR包,但是由于它们互相之间版本不兼容而导致项目启动失败等问题,
而现在这些版本之间管理都由Spring Boot来帮助我们完成,其互相之间出现冲突就基本上不复存在了。
因此,Spring官方强烈建议用户在使用Spring Boot,不要再对已经定义好的Spring版本进行重写。@Autowired
private Environment env;springboot在启动的时候会自动将 application.proeprties 装载到 Evnironment中
获取 application.proeprties 中的配置项只需要
env.getProperty(“jdbc.url”) 这样就可以或者使用 @Value 注解
比如
@Value(“${jdbc.driverClass}”)
private String jdbcDriverClass;