如何修复xml-less自动装配服务

时间:2013-02-21 18:27:00

标签: spring jersey grizzly

当我直接在我的main()中调用服务时,我可以查询数据库并且工作正常。当泽西请求进来并将JSON映射到NewJobRequest时,由于@Autowire失败,我无法使用我的服务。

我的应用

public class Main {

    public static final URI BASE_URI = getBaseURI();

    private static URI getBaseURI() {
        return UriBuilder.fromUri("http://localhost/").port(9998).build();
    }

    protected static HttpServer startServer() throws IOException {
        ResourceConfig rc = new PackagesResourceConfig("com.production.api.resources");
        rc.getFeatures()
            .put(JSONConfiguration.FEATURE_POJO_MAPPING, true);

        return GrizzlyServerFactory.createHttpServer(BASE_URI, rc);
    }

    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);

        //if this is uncommented, it'll successfully query the database
        //VendorService vendorService = (VendorService)ctx.getBean("vendorService");
        //Vendor vendor = vendorService.findByUUID("asdf"); 

        HttpServer httpServer = startServer();
        System.out.println(String.format("Jersey app started with WADL available at " + "%sapplication.wadl\nTry out %shelloworld\nHit enter to stop it...", BASE_URI, BASE_URI));
        System.in.read();
        httpServer.stop();
    }
}

我的资源(控制器):

@Component
@Path("/job")
public class JobResource extends GenericResource {
    @Path("/new")
    @POST
    public String New(NewJobRequest request) {
        return "done";
    }
}

Jersey将JSON帖子映射到:

@Component
public class NewJobRequest {

    @Autowired
    private VendorService vendorService;

    @JsonCreator
    public NewJobRequest(Map<String, Object> request) {
        //uh oh, can't do anything here because @Autowired failed and vendorService is null
    }
}

VendorService:

@Service
public class VendorService extends GenericService<VendorDao> {

    public Vendor findByUUID(String uuid) {
        Vendor entity = null;
        try {
            return (Vendor)em.createNamedQuery("Vendor.findByUUID")
                    .setParameter("UUID", uuid)
                    .getSingleResult();
        } catch (Exception ex) {
            return null;
        }
    }
}

-

@Service
public class GenericService<T extends GenericDao> {

    private static Logger logger = Logger.getLogger(Logger.class.getName());

    @PersistenceContext(unitName = "unit")
    public EntityManager em;

    protected T dao;

    @Transactional
    public void save(T entity) {
        dao.save(entity);
    }
}

我的服务配置:

@Configuration
public class Config {
    @Bean
    public VendorService vendorService() {
        return new VendorService();
    }
}

我的配置

@Configuration
@ComponentScan(basePackages = {
        "com.production.api",
        "com.production.api.dao",
        "com.production.api.models",
        "com.production.api.requests",
        "com.production.api.requests.job",
        "com.production.api.resources",
        "com.production.api.services"
})
@Import({
        com.production.api.services.Config.class,
        com.production.api.dao.Config.class,
        com.production.api.requests.Config.class
})
@PropertySource(value= "classpath:/META-INF/application.properties")
@EnableTransactionManagement
public class Config {
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
    private static final String PROPERTY_NAME_DATABASE_USER = "db.user";
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";

    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
    private static final String PROPERTY_NAME_HIBERNATE_FORMAT_SQL = "hibernate.format_sql";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";

    @Resource
    Environment environment;

    @Bean
    public DataSource dataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();

        dataSource.setUrl(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
        dataSource.setUser(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_USER));
        dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));

        return dataSource;
    }

    @Bean
    public JpaTransactionManager transactionManager() throws ClassNotFoundException {
        JpaTransactionManager transactionManager = new JpaTransactionManager();

        transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject());

        return transactionManager;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() throws ClassNotFoundException {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceUnitName("unit");
        entityManagerFactoryBean.setPackagesToScan(environment.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);

        Properties jpaProperties = new Properties();
        jpaProperties.put(PROPERTY_NAME_HIBERNATE_DIALECT, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        jpaProperties.put(PROPERTY_NAME_HIBERNATE_FORMAT_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_FORMAT_SQL));
        jpaProperties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, environment.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));

        entityManagerFactoryBean.setJpaProperties(jpaProperties);

        return entityManagerFactoryBean;
    }
}

2 个答案:

答案 0 :(得分:0)

@Path@POST注释是JAX-RS,而不是Spring。所以容器本身就是在实例化你的端点,而不需要知道Spring bean。您很可能没有获得任何Spring日志记录,因为Spring根本没有被使用。

答案 1 :(得分:0)

我已经找到了问题并在此处发表了博客:http://blog.benkuhl.com/2013/02/how-to-access-a-service-layer-on-a-jersey-json-object/

与此同时,我也将在这里发布解决方案:

我需要使用Spring已创建的bean,因此我使用了Spring的ApplicationContextAware

public class ApplicationContextProvider implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext (ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}

然后在我的对象中使用该静态上下文引用进行映射,以便我可以在服务中执行查找:

public class NewJobRequest {

    private VendorService vendorService;

    public NewJobRequest() {
        vendorService = (VendorService) ApplicationContextProvider.getApplicationContext().getBean("vendorService");
    }

    @JsonCreator
    public NewJobRequest(Map<String, Object> request) {
        setVendor(vendorService.findById(request.get("vendorId")); //vendorService is null
    }
    ....
}