代码之家  ›  专栏  ›  技术社区  ›  Ben

如何修复服务的无xml自动布线

  •  1
  • Ben  · 技术社区  · 13 年前

    当我直接在我的 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
        }
    }
    

    供应商服务:

    @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 回复  |  直到 13 年前
        1
  •  0
  •   artbristol    13 年前

    这个 @Path @POST 注释是JAX-RS,而不是Spring。因此,容器是在自己实例化端点的,而不了解Spring bean。您很可能没有得到任何Spring日志记录,因为根本没有使用Spring。

        2
  •  0
  •   Ben    13 年前

    我已经弄清楚了这个问题,并在这里发了博客: 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
        }
        ....
    }
    
    推荐文章