spring cloud使用JpaRepository,dao层无法注入容器,调试报空指针的解决思路

     公司岗位调整,我从一个安卓开发转后台开发,以前在其他公司也接触过后台,那时公司用的是ssm框架,不过安卓还是
主业务,后台业务也只是略而兼之,并未深研,想着公司这次给机会做后台,本着技多不压身,就欣然接受,此时已经2019年了,微服务方兴未艾,如火如荼,自然我也就去学习微服务了,在学习过程中,spring cloud使用JpaRepository,编译是能通过,在调试接口时报了一个空指针,经过debug调试,是接口

public interface ProductInfoRepository extends JpaRepository {
   List findByProductStatus(List productIdStatus);

}

 在下面的service中

@Service
public class ProductInfoServiceImpl implements IProductInfoService {
    @Autowired(required = false)
    private ProductInfoRepository productInfoRepository;

    @Override
    public List getProductList() {
      List integerList = new ArrayList<>();
      integerList.add("1");
      List productInfoList = productInfoRepository.findByProductStatus(integerList);
      return productInfoList;
    }
}


      其中private ProductInfoRepository productInfoRepository是null的,ProductInfoRepository没有注入到容器中
调试几遍还是报空指针,只好求助百度,可以说困扰了我4天,都没有找到spring cloud使用JpaRepository报空指针的解决方案
网上找到的以下方案,都试了,都无用
1.private ProductInfoRepositoryproductInfoRepository是不是没有用@Autowired(required = false)注解,检查自己写的代码,是注解了
2.public interface ProductInfoRepository加上@Component,@Repository, 加上后,调试结果,service中的productInfoRepository还是为null,继续报空指针
3.controller和service中的方法是不是private的,检查自己的代码,方法都是public,排除该怀疑对象
4.entity实体类加上@table,@colum,调试结果,service中的productInfoRepository还是为null,报空指针
5.甚至自己怀疑是不是(required = false)了,去掉该配置,自然就报了另外一个异常,方案还是不对
6.Application上加上

@ComponentScan(basePackages = {"com.chengfeng.product.controller","com.chengfeng.product.service"}),
@EntityScan(basePackages = "com.chengfeng.product.entity")
@EnableJpaRepositories(basePackages = "com.chengfeng.product.repository")

即代码为


@SpringBootApplication()(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.chengfeng.product.controller","com.chengfeng.product.service"}),
@EntityScan(basePackages = "com.chengfeng.product.entity")
@EnableJpaRepositories(basePackages = "com.chengfeng.product.repository")
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }

}


上述加上,调试结果,service中的productInfoRepository还是为null,报空指针,
7.检查定义的entity实体类ProductInfo中的属性字段是否与数据库中一致,一一检查,都一一对应,排除该怀疑对象
8.当然什么重启了,清除缓存,说jar包冲突的,把原来的jar包全部清除重新下载,依然无用。
说实话,搞了几天都快崩溃了,放弃心又不甘,元气恢复,又鬼使神差继续调试。
9.是不是new service对象或者new  ProductInfoRepository对象了,检查自己的代码,也排除该怀疑对象
10.最后实在没有脾气了,把ProductInfoRepository定义的接口屏蔽掉,用JpaRepository原生生成的默认方法,还是报空指针。

最后,看了一眼ProductApplication 

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }
}


死马当活马医,把(exclude = DataSourceAutoConfiguration.class)去掉,将原来出现的

Error creating bean with name 'entityManagerFactory' defined in class path resource
 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]

异常暴露出来,把这个问题解决,看能不能顺便把空指针解决,然而运行后先报

HHH000342: Could not obtain connection to query metadata : Driver com.mysql.cj.jdbc.Driver claims to not accept jdbcUrl, 
jdbc:mysql:http://localhost:3306/product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC

了一个新的问题,再报

 Exception encountered during context initialization - cancelling refresh attempt: 
 org.springframework.beans.factory.BeanCreationException:
 Error creating bean with name 'entityManagerFactory' defined in class path resource
 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: 
 Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException:
 Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]


 根据网上资料,application.properties中的spring.datasource.***肯定有问题,仔细看了几遍application.properties:

spring.application.name=product

server.port=8081
eureka.client.service-url.defaultZone: http://localhost:8761/eureka/

spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql:http://localhost:3306/product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = 123456

spring.jpa.hibernate.ddl-auto = update

# 方便jpa调试的配置
spring.jpa.show-sql = true

也没发现什么问题,最后经过对比,发现jdbc:mysql后面多了个http,之前没有开发配置过数据库,也不知这里到底如何配置,什么时候这里多了个http,难道是因为多了个http,抱着疑问的态度改成

spring.datasource.url= jdbc:mysql://localhost:3306/product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC


 奇迹出现了,项目成功运行起来,最后接口调试,service中的productInfoRepository也成功注入容器了了,接口也调通了,也不报空指针了。此刻我已经知道,肯定是ProductInfoRepository中的接口写的不符合jpa规范,所以才造成ProductInfoRepository不能成功注入容器,将原来的方法:

// List findByProductStatus(List productIdStatus);


 放开,运行,果然是又报错,

@SpringBootApplication加上(exclude = DataSourceAutoConfiguration.class),运行项目,错误消失,接口调试,继续报空指针,
至于为什么这个方法造成jpa不能注入容器,想必是这种接口定义方法不符合jpa规范,jpa识别不了。

最终,spring cloud使用jpa,要避免Repository不能注入容器,防止空指针的发生,除了排除上述10点怀疑对象,还要注意以下3点:

(1)@SpringBootApplication不能加(exclude = DataSourceAutoConfiguration.class)

(2)application.properties中关于数据库的配置一定要准确

(3)继承JpaRepository的dao层接口中自己定义的方法一定要符合jpa规范,按jpa的提示定义相关防范,不要自己随意命名,

最后附上spring cloud demo的部分

pom.xml代码



    4.0.0

    
        org.springframework.boot
        spring-boot-starter-parent
        2.2.1.RELEASE
         
    

    com.chengfeng
    product
    0.0.1-SNAPSHOT
    product
    Demo project for Spring Boot

    
        UTF-8
        UTF-8
        1.8
        Hoxton.RC2
    

    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-data-jpa
        

        
            mysql
            mysql-connector-java
        

        
            org.springframework.boot
            spring-boot-starter-test
        

        
            com.fasterxml.jackson.core
            jackson-annotations
        

        
            org.springframework.boot
            spring-boot-starter-actuator
        

        
            junit
            junit
        
    

    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/milestone
        
    


application.properties代码:

spring.application.name=product

server.port=8081
eureka.client.service-url.defaultZone: http://localhost:8761/eureka/

spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://localhost:3306/product?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = 123456

spring.jpa.hibernate.ddl-auto = update

# 方便jpa调试的配置
spring.jpa.show-sql = true
package com.chengfeng.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }

}

 controller层ProductController.java代码

package com.chengfeng.product.controller;


@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private IProductInfoService productInfoService;

    @GetMapping("/list")
    public void getProductList() {
        System.out.println("开始获取getProductList");
        //  1.查询所有商品
        List productInfoList = productInfoService.getProductList();
        System.out.println("获取的getProductList == ",productInfoList);

    }
}

Entity实体类ProductInfo.java代码

package com.chengfeng.product.entity;

import javax.persistence.Entity;
import javax.persistence.Id;
import java.math.BigDecimal;
import java.util.Date;

/**
 * 这里表名会自动转换,数据库中驼峰会是下划线,下面的变量也是
 */

@Entity
public class ProductInfo {

    @Id
    private String productId;

    /** 名字. */
    private String productName;

    /** 单价. */
    private BigDecimal productPrice;

    /** 库存. */
    private Integer productStock;

    /** 描述. */
    private String productDescription;

    /** 小图. */
    private String productIcon;

    /** 状态, 0正常1下架. */
    private Integer productStatus;

    /** 类目编号. */
    private Integer categoryType;

    private Date createTime;

    private Date updateTime;

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public BigDecimal getProductPrice() {
        return productPrice;
    }

    public void setProductPrice(BigDecimal productPrice) {
        this.productPrice = productPrice;
    }

    public Integer getProductStock() {
        return productStock;
    }

    public void setProductStock(Integer productStock) {
        this.productStock = productStock;
    }

    public String getProductDescription() {
        return productDescription;
    }

    public void setProductDescription(String productDescription) {
        this.productDescription = productDescription;
    }

    public String getProductIcon() {
        return productIcon;
    }

    public void setProductIcon(String productIcon) {
        this.productIcon = productIcon;
    }

    public Integer getProductStatus() {
        return productStatus;
    }

    public void setProductStatus(Integer productStatus) {
        this.productStatus = productStatus;
    }

    public Integer getCategoryType() {
        return categoryType;
    }

    public void setCategoryType(Integer categoryType) {
        this.categoryType = categoryType;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}

dao层ProductInfoRepository.java代码

package com.chengfeng.product.repository;

import com.chengfeng.product.entity.ProductInfo;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ProductInfoRepository extends JpaRepository {
  List findByProductStatus(Integer productStatus);
}

服务层ProductInfoServiceImpl.java代码

package com.chengfeng.product.service;

import com.chengfeng.product.common.ProductStatusEnum;
import com.chengfeng.product.entity.ProductInfo;
import com.chengfeng.product.repository.ProductInfoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;


@Service
public class ProductInfoServiceImpl implements IProductInfoService {
    @Autowired(required = false)
    private ProductInfoRepository productInfoRepository;

    @Override
    public List getProductList() {
        List productInfoList = productInfoRepository.findByProductStatus(ProductStatusEnum.UP.getCode());
        return productInfoList;
    }
}

 

你可能感兴趣的:(spring,cloud)