【问题标题】:Autowiring issue with SpringBootSpring Boot 的自动装配问题
【发布时间】:2015-10-07 08:16:23
【问题描述】:

我有一个像下面这样的课程:

package com.company.data.render.model
@RestController
public class ControllerClass {

@Autowired
ApplicationPropertiesServiceImpl services;

@RequestMapping(value = "/node1", method = RequestMethod.GET)
@ResponseBody
public ParentNode getNode1() 
{


    Child node = new Child();
    List<Map<String, Object>> properties properties = services.getData("A",xxx);
    node.addtree();
    node.setProperties(properties);
    return node;
}
 }   -------------------------------------------------------------------------------

package com.company.data.service;
@Component
public List<Map<String, Object>> getData(String type,String name) 
{
        if(type.equalsIgnoreCase("A"))
        {
            String sql = "select * from data.data_properties(?)";
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql,host);
            return rows;
        }else if(properties.equalsIgnoreCase("B"))
        {
            String sql = "select * from data.application_properties(?)";
            List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql,host);
            return rows;
        }

}

-------------------------------------------------------------------------------
package com.company.data.render.model;

@Component
public class Child {

@Autowired
ApplicationPropertiesServiceImpl services;


public void addtree()
{
List<Map<String, Object>> properties=services.getData("B", "xxy");

}
}

如何访问 Child 类中的 getdata() 函数。虽然我有 service 对象,但我得到空指针异常strong>自动装配 ApplicationPropertiesServiceImpl

【问题讨论】:

  • 您拼错了注释,它应该是@Autowired。但是,将控制器连接到另一个组件是一个坏主意。如果您将公共代码提取到单独的 @Service bean 中并从控制器和您的 Child 类中引用该 bean 会更好。当然,您还必须正确设置应用程序上下文并对其进行初始化。
  • 最好把逻辑分开,目前你的控制器做的事情太多了。我建议你做 2 个类:一个服务和一个 DAO(存储库)。存储库将为您提供 db 的结果。并且服务会有DAO对象+一些业务。两个控制器都将自动连接服务。
  • @korogue --即使我创建了一个单独的类..我将如何在两个类中获得相同的服务对象??
  • 使用注解@Autowired

标签: java spring spring-boot


【解决方案1】:

看来您将拥有 2 个控制器。

显然你的控制器做得太多了。将一个控制器注入另一个控制器并不是一个好主意。

我建议你做一个服务和一个存储库:

模型从 Controller 接收到大量数据,因此我建议创建一个类以使其更清晰,因为返回 Map 过于抽象,使代码难以阅读。

public class CarProperties {
    private Integer id;
    private String name;
    private Integer age;
    private String color;
    //setters and gettters
    ....
}

服务:

public interface CarPropertiesService {
   public List<CarProperties> findAll(String type);
}

@Service("CarPropertiesService")
public class CarPropertiesServiceImpl implements CarPropertiesService {
   @Autowired
   private CarPropertiesDAO carPropertiesDAO;

   public List<CarProperties> findAll(String type) {
      List<CarProperties> result = new ArrayList<>();
      if ("XXX".equalsIgnoreCase(type)) {
         List<Map<String, Object>> carPropertiesList = carPropertiesDAO.findAll();
         for(Map<String, Object> carProperties : carPropertiesList) {
            result.add(getCarPropertiesInstance(carProperties));
         }

      }
      return result;
   }

   private CarProperties getCarPropertiesInstance(Map<String, Object> properties) {
      CarProperties instance = new CarProperties();
      instance.setId(properties.get("id"));
      instance.setName(properties.get("name"));
      ...
      return instance;
   }
}

道:

public interface CarPropertiesDAO {
   public List<Map<String, Object>> findAll();
}

@Repository("CarPropertiesDAO")
public class CarPropertiesDAOImpl implements CarPropertiesDAO {
   ...
   public List<Map<String, Object>> findAll() {
      String sql = "select * from data.car_properties(?)";
      return jdbcTemplate.queryForList(sql,host);
   }
}

最后您的控制器将使用该服务:

@RestController
public class ControllerClass {
    @Autowired
    private CarPropertiesService carPropertiesService;

    @RequestMapping(value = "/node1", method = RequestMethod.GET)
    @ResponseBody
    public ParentNode getNode1() 
    {
       List<CarProperties> properties = carPropertiesService.findAllByType("XXX");
       return properties;

    }

    @RequestMapping(value = "/prop/{type}/{name}", method = RequestMethod.GET)
    @ResponseBody
    public List<CarProperties> getData(@PathVariable String type,@PathVariable String name) 
   {
      List<CarProperties> rows = carPropertiesService.findAllByType(type);    
      ...
   }
}

@Controller
public class Controller2 {
   @Autowired
   CarPropertiesService carPropertiesService;


   public void addtree(){
      List<CarProperties> rows = carPropertiesService.findAllByType("XXX");
   }
}

Resuming:控制器不应该担心业务,而只需要返回数据。服务应该在业务所在的地方,比如计算、数据交换等……你可以清楚地看到它是用于 DB 操作的 DAO 类。还要记住对 DAO 对象的访问应该在 Services/Facedes 中,在推荐的 Controller 中使用它。因此,使用这种结构,您的代码将变得更加可重用且易于维护。

【讨论】:

  • 但是两个 dao 和 impl 类的必要性是什么...不是很混乱吗
  • 不是真的,一个是接口,另一个是类。您可以将接口重用于不同的类。
  • 这个解决方案不适合我的问题..无论如何感谢 Becoz 这不是我正在查询的表..这是我通过查询执行的函数..
  • 那么函数应该在服务中
【解决方案2】:

请试试这个:-

@Component
@ComponentScan(basePackages="<provide your base pkg where it will scan for the component ControllerClass>")
@ConditionalOnBean(ControllerClass.class)
public class Child {
  @Autowired(required=true)
  private ControllerClass controllerClass;

  public void addtree(){
    controllerClass.getData("XXX",xxx)
  }
}

【讨论】:

  • 请检查我上面的更新建议以包含注释@ComponentScan。
  • 这正是我在项目中提到的..没有其他配置
  • 你的项目是spring boot项目吗??
  • 是的..这是一个spring boot项目
  • 我刚刚将您的代码导入了一个 Spring Boot 项目,并且工作正常。无需更改您的代码即可进行自动装配或任何操作,Spring boot 应用程序会自动启用 @ComponentScan。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
  • 2019-05-03
  • 2015-02-26
  • 1970-01-01
  • 2018-05-08
  • 2016-10-03
相关资源
最近更新 更多