自动装配Spring 3.2独立应用程序失败 [英] Autowiring a Spring 3.2 standalone application fails

查看:98
本文介绍了自动装配Spring 3.2独立应用程序失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次在stackoverflow上找不到解决问题的方法:

This is the first time I can't find a solution to my problem on stackoverflow:

我正在尝试使用基于注释的自动装配创建一个可执行jar的独立应用程序,但是我无法获得可运行的jar文件(从Eclipse导出为可运行的JAR文件)来完成它的工作.它确实可以直接从Eclipse作为Java应用程序运行,而不是通过控制台> java -jar test.jar作为独立应用程序运行.

I'm trying to create an executable-jar standalone application with annotation-based autowiring, but I can't get the runnable jar file (exported from Eclipse as runnable JAR file) to do it's job. It does run as Java application from Eclipse directly, just not as standalone app via console > java -jar test.jar.

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handler': Injection of autowired dependen
cies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.serv
ice.UserService com.example.controller.TestHandler.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionEx
ception: No qualifying bean of type [com.example.service.UserService] found for dependency: expected at least 1 bean which qualifies as auto
wire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBe
anPostProcessor.java:288)

我尝试遵循此博客上描述的手动初始化自动装配"模式来避免此类问题: http ://sahits.ch/blog/?p = 2326 无济于事. 请注意,我也使用了没有persistence.xml(因此< tx:annotation-driven/>)的Hibernate JPA,并且不会被我使用的两个数据库所阻塞,当在Eclipse中运行时,它工作正常.

I tried to avoid such problems by following the pattern 'Initialize autowiring manually' described on this blog: http://sahits.ch/blog/?p=2326 to no avail. Note that I'm also using Hibernate JPA without a persistence.xml (therefore <tx:annotation-driven/> ) - and don't get obstructed by the two databases I use, it works fine when running from within Eclipse.

Main.java:

Main.java:

public class Main {
    @Autowired
    private TestRunner testRunner;

    public Main() {
        final ApplicationContext context = new ClassPathXmlApplicationContext("app-context.xml");
        AutowireCapableBeanFactory acbFactory = context.getAutowireCapableBeanFactory();
        acbFactory.autowireBean(this);
    }

    public static void main(String[] args) throws Exception {
        Main main = new Main();

        main.testRunner.run();
    }
}

TestRunner.java:

TestRunner.java:

@Component
public class TestRunner {
    @Autowired
    Handler handler;

    public void run() {
        handler.doTest();
    }
}

TestHandler.java(groupId和groupName将在以后的阶段中设置):

TestHandler.java (groupId and groupName will be set in a later stage):

@Controller
public class TestHandler implements Handler {
    private static Log syslog = LogFactory.getLog(TestHandler.class);

    @Autowired
    private UserService userService;

    @Autowired
    private GroupService groupService;

    private Long groupId;
    private String groupName;

    public void doTest() {
        if (groupId != null) {
            List<User> users = userService.loadUsersByGroupId(groupId);
            syslog.debug("Amount of users found: " + users.size());
        } else {
            syslog.debug("groupId is null");
        }

        if (groupName != null) {
            List<Group> groups = groupService.loadGroupsByName(groupName);
            syslog.debug("Amount of groups found: " + groups.size());
        } else {
            syslog.debug("groupName is null");
        }

    }

    public void setGroupId(Long groupId) {
        this.groupId = groupId;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }
}

UserServiceImpl.java:

UserServiceImpl.java:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserDAO userDAO;

    @Override
    public List<User> loadUsersByGroupId(long id) {
        return userDAO.findAllByGroupId(id);
    }

...

UserDAOImpl.java:

UserDAOImpl.java:

@Repository
@Transactional("db1")
public class UserDAOImpl implements UserDAO {

    @PersistenceContext(unitName="entityManagerDb1")
    private EntityManager em;

    @SuppressWarnings("unchecked")
    @Override
    public List<User> findAllByGroupId(long id) {
        Query query = em.createQuery("select distinct u from User u " +
                "where u.groupId = :groupId");
        query.setParameter("groupId", id);

        return query.getResultList();
    }

    ...

app-context.xml(使用注释配置的JPA,使用两个数据库):

app-context.xml (uses annotation-configured JPA, uses two dbs):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/tx
            http://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
        "
        >

    <context:annotation-config/>

    <context:component-scan base-package="com.example"/>

    <!-- db1 -->
    <bean id="dataSourceDb1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
      <property name="driverClass" value="com.mysql.jdbc.Driver" />
      <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=UTF-8" />
      <property name="user" value="root" />
      <property name="password" value="root" />
      <property name="minPoolSize" value="5" />
      <property name="maxPoolSize" value="10" />
      <property name="maxStatements" value="0" />
      <property name="preferredTestQuery" value="SELECT 1" />
      <property name="idleConnectionTestPeriod" value="600" />
    </bean>

     <bean id="entityManagerFactoryDb1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="entityManagerDb1"/>
         <property name="dataSource" ref="dataSourceDb1"/>
        <property name="packagesToScan">
            <list>
                <value>com.example.domain.db1</value>
            </list>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false"/>
                <property name="generateDdl" value="true"/>
                <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            </bean>
        </property>

        <property name="jpaProperties">
            <props>
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
               <prop key="hibernate.connection.show_sql">true</prop>
               <prop key="hibernate.hbm2ddl.auto">validate</prop>
               <prop key="hibernate.use_outer_join">true</prop>
               <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
               <prop key="hibernate.connection.useUnicode">true</prop>
            </props>
        </property>

    </bean>

    <!-- Configure transaction manager for JPA -->
    <bean id="transactionManagerDb1" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoryDb1"/>
        <qualifier value="db1"/>
    </bean>

    <!-- db2 -->
    <bean id="dataSourceDb2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
      <property name="driverClass" value="com.mysql.jdbc.Driver" />
      <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/db2?characterEncoding=UTF-8" />
      <property name="user" value="root" />
      <property name="password" value="root" />
      <property name="minPoolSize" value="5" />
      <property name="maxPoolSize" value="10" />
      <property name="maxStatements" value="0" />
      <property name="preferredTestQuery" value="SELECT 1" />
      <property name="idleConnectionTestPeriod" value="600" />
    </bean>

     <bean id="entityManagerFactoryDb2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="entityManagerDb2"/>
         <property name="dataSource" ref="dataSourceDb2"/>
        <property name="packagesToScan">
            <list>
                <value>com.example.domain.db2</value>
            </list>
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false"/>
                <property name="generateDdl" value="true"/>
                <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            </bean>
        </property>

        <property name="jpaProperties">
            <props>
               <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
               <prop key="hibernate.connection.show_sql">true</prop>
               <prop key="hibernate.hbm2ddl.auto">validate</prop>
               <prop key="hibernate.use_outer_join">true</prop>
               <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
               <prop key="hibernate.connection.useUnicode">true</prop>
            </props>
        </property>

    </bean>

    <bean id="transactionManagerDb2" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoryDb2"/>
        <qualifier value="db2"/>
    </bean>

    <tx:annotation-driven />

</beans>

让我发疯的是,在Eclipse中运行它确实按预期运行. Eclipse导出功能是否有所限制?对创建可运行jar文件的其他框架有任何提示吗?

It drives me crazy that running it inside Eclipse just works as expected. Is the Eclipse export feature somewhat limited? Any hint to another framework for creating runnable jar files?

推荐答案

在Eclipse中运行它时,所有Spring依赖项和其他依赖项都被加载到类路径中,但是当您将应用程序导出为jar时,只会导出您的类,而不是依赖项类.

When you run it inside Eclipse all the Spring dependencies and others are loaded into your classpath, but when you export you application as a jar, only your classes get exported, not the dependencies classes.

通常有两种方法可以实现独立的jar.您可以创建超级罐"(请参见),您所有的依赖项jar都扩展为一个罐.但是,此方法可能会存在风险,因为如果这些jar文件具有相同的文件名(例如:META-INF中的相同配置文件),它们可能会相互覆盖

There are generally two way you can achieve a standlone jar. You can create an 'uber jar' (see Is it possible to create an "uber" jar containing the project classes and the project dependencies as jars with a custom manifest file?) where all you dependency jars got expanded into one single jar. However this method could be risky because if the jars have same file names (eg: same config file inside META-INF) they can overwrite each other

另一种更合适的方法是使用maven-dependency-plugin(请参阅dependency:copy)将所有依赖项复制到文件夹"dependencies"中.然后用

The other more appropriate method is to use maven-dependency-plugin (see dependency:copy) to copy all your dependency into a folder "dependencies". And then run your jar with

java -cp "myjar.jar;dependencies/*" org.mycompany.MainClass

这实际上不是一个独立的jar,而是一个独立的文件夹.缺点是每次添加/删除依赖项(例如,从maven中)时,都必须对依赖项文件夹执行相同的操作

This isn't really a standalone jar, but more a standalone folder. The downside is everytime you add/remove the dependencies (eg: from maven) you have to do the same to your dependencies folder

这篇关于自动装配Spring 3.2独立应用程序失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆