Spring注释@Value - 我错过了什么?

时间:2014-12-02 21:03:06

标签: java spring annotations

我继承了一些Java代码。几个类的实例变量是从/WEB-INF/servlet.properties中的属性值初始化的,如下所示:

@Value("${context.root}")
private String contextRoot;

当我在新类中尝试此操作时,实例变量未初始化。我的类的构造类似于有效的类,但它位于不同的包中(com.company.app.utilities与com.company.app.service)两者都导入相同的类:

import org.springframework.beans.factory.annotation.Value;

两者都有相应的公共getter和setter方法。

我已经查看了一些Spring文档和/WEB-INF/applicationContext.xml,但我没有看到任何需要配置的明显内容。

非常感谢任何帮助。

更新: 我在日志中看到以下条目:

[localhost-startStop-1] 03 Dec 2014 02:47:10,791 INFO : org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from ServletContext resource [/WEB-INF/servlet.properties]
[localhost-startStop-1] 03 Dec 2014 02:47:10,938 INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@601e8f7d: defining beans [...,contactServiceImpl,s3Transfer,...]; parent: org.springframework.beans.factory.support.DefaultListableBeanFactory@32f5f812

我已经从日志条目中省略了所有其他单例,以突出显示原始类和我的类都在列表中;但是,我创建了一个构造函数,而原始类没有构造函数。日志中的下一行是我在getter方法中抛出的异常,当值为null时,在构造函数中捕获:

[localhost-startStop-1] 03 Dec 2014 02:47:12,730 ERROR: com.company.app.utilities.S3Transfer - bucketName is null!
java.lang.Exception: bucketName is null!
    at com.company.app.utilities.S3Transfer.getBucketName(S3Transfer.java:129)
    at com.company.app.utilities.S3Transfer.<init>(S3Transfer.java:48)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1000)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:953)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:599)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:518)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:459)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)

...

我应该删除构造函数吗?如果是这样,是否有额外的Spring配置来实例化这个类的单例?感谢。

更新2014-12-03: 我想我已经远离Java了,因为我最后一次编写AOP时,没有Spring Framework,而且让我有点困惑。当你说&#34;由Spring&#34;实例化时,这是否意味着将@Autowired放在使用我的新类的类中?我已经做了这个改变,并且我已经重写了我的类来实现一个接口,但现在Tomcat无法正常重启。代码,属性和日志如下:

package com.company.app.utilities;

import com.company.app.bean.Contact;
import java.io.InputStream;

public interface S3Transfer {
    String storeContactProfilePicture(Long idUser, Contact contact);
    String storeContactProfilePicture(Long idUser, Long idContact, InputStream inStream);
    String storeUserProfilePicture(Long idUser, String fileName, String accountType);
}

package com.company.app.utilities;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.company.app.bean.Contact;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;

public class S3TransferImpl implements S3Transfer {

    private final AmazonS3 s3client = new AmazonS3Client();

    private final Logger logger = Logger.getLogger(getClass());

    @Value("${context.root}")
    private String contextRoot;

    @Value("${s3.bucket.name}")
    private String bucketName;

    @Value("${contact.profile.picture}")
    private String contactProfilePictureKey;

    @Value("${user.profile.picture}")
    private String userPictureKey;

    public String storeContactProfilePicture(Long idUser, Contact contact) {
    String keyName = getContactProfilePictureKey().replaceAll("<<idUsr>>", idUser.toString()).replaceAll("<<idContact>>", contact.getIdContact().toString());
    String fileName = contact.getPicture();

    storeObjectFromFileName(fileName, keyName);
    return contextRoot + keyName;
    }

    public String storeContactProfilePicture(Long idUser, Long idContact, InputStream inStream) {
    String keyName = getContactProfilePictureKey().replaceAll("<<idUsr>>", idUser.toString()).replaceAll("<<idContact>>", idContact.toString());

    storeObject(inStream, keyName);
    return contextRoot + keyName;
    }

    public String storeUserProfilePicture(Long idUser, String fileName, String accountType) {
    String keyName = getUserPictureKey().replaceAll("<<idUsr>>", idUser.toString()).replace("<<socialNetwork>>", accountType);

    storeObjectFromFileName(fileName, keyName);
    return contextRoot + keyName;
    }

    private void storeObjectFromFileName(String fileName, String keyName) {
    try {
        logger.info("Uploading " + fileName + " to " + keyName);
        InputStream inStream = new URL(fileName).openStream();
        storeObject(inStream, keyName);
    } catch (IOException e) {
        logger.error(e.getMessage(), e);
    }
    }

    private void storeObject(InputStream inStream, String keyName) {
    try {
        this.s3client.putObject(new PutObjectRequest(getBucketName(), keyName, inStream, null));
    } catch (AmazonServiceException ase) {
        logger.error("Caught an AmazonServiceException, which "
            + "means your request made it "
            + "to Amazon S3, but was rejected with an error response"
            + " for some reason.");
        logger.error("Error Message:    " + ase.getMessage());
        logger.error("HTTP Status Code: " + ase.getStatusCode());
        logger.error("AWS Error Code:   " + ase.getErrorCode());
        logger.error("Error Type:       " + ase.getErrorType());
        logger.error("Request ID:       " + ase.getRequestId());
    } catch (AmazonClientException ace) {
        logger.error("Caught an AmazonClientException, which "
            + "means the client encountered "
            + "an internal error while trying to "
            + "communicate with S3, "
            + "such as not being able to access the network.");
        logger.error("Error Message: " + ace.getMessage());
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    }

    public String getContextRoot() {
    return contextRoot;
    }

    public void setContextRoot(String contextRoot) {
    this.contextRoot = contextRoot;
    }

    public String getBucketName() {
    return bucketName;
    }

    public void setBucketName(String bucketName) {
    this.bucketName = bucketName;
    }

    private String getContactProfilePictureKey() {
    return contactProfilePictureKey;
    }

    private void setContactProfilePictureKey(String contactProfilePictureKey) {
    this.contactProfilePictureKey = contactProfilePictureKey;
    }

    private String getUserPictureKey() {
    return userPictureKey;
    }

    private void setUserPictureKey(String userPictureKey) {
    this.userPictureKey = userPictureKey;
    }

}

使用S3Transfer的类现在具有以下代码:

@Autowired
private S3Transfer s3Transfer;

/WEB-INF/applicationContext.xml和/WEB-INF/app-web-servlet.xml都在复杂的bean元素中包含以下元素:

<context:annotation-config />
<context:component-scan base-package="com.company.app" />
<context:property-placeholder location="/WEB-INF/servlet.properties" />

当我重新启动Tomcat时,初始化失败。以下是一些相关的日志条目:

    [localhost-startStop-1] 03 Dec 2014 18:39:03,407 INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
[localhost-startStop-1] 03 Dec 2014 18:39:03,926 INFO : org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
[localhost-startStop-1] 03 Dec 2014 18:39:05,990 INFO : org.springframework.context.annotation.ClassPathBeanDefinitionScanner - JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
[localhost-startStop-1] 03 Dec 2014 18:39:07,983 INFO : org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from ServletContext resource [/WEB-INF/servlet.properties]
[localhost-startStop-1] 03 Dec 2014 18:39:08,708 INFO : org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@63655d7a: defining beans [... {long list, but s3TransferImpl is not in the list} ...]; root of factory hierarchy
[localhost-startStop-1] 03 Dec 2014 18:39:10,667 INFO : org.springframework.jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: com.mysql.jdbc.Driver
[localhost-startStop-1] 03 Dec 2014 18:39:20,152 ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0]; nested exception is ... {long list of nested exceptions}...; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.company.app.utilities.S3Transfer] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:329)

更新2014-12-03 14:50美国东部时间: 显然,我的接口和类都需要@Service注释,因为Tomcat成功重启。这个注释的目的是什么?

2 个答案:

答案 0 :(得分:0)

需要将新类的包(即com.company.app.service)添加到具有spring配置的xml文件中。 您需要将其添加到spring XML配置文件

<beans>
    <context:component-scan base-package="com.package.containing.yourclass" />
</beans>

您需要这样,以便Spring了解扫描注释和/或创建bean所需的类。

答案 1 :(得分:-1)

请您分享您尝试访问变量的代码。如果它在contructor中,那么你将得到错误。由于在加载过程中被单独填充的单例bean将无法从属性配置器访问这些值。您可以考虑将代码移动到in-it方法,以便在访问字段时设置变量。 此外,确认您的班级是否由弹簧容器即时,而不是通过其他方式如新操作员