这是我第一次在stackoverflow上找不到问题的解决方案:
我正在尝试创建一个带有基于注释的自动装配的可执行jar独立应用程序,但我无法获得可运行的jar文件(从Eclipse导出为可运行的JAR文件)来完成它的工作。它确实直接从Eclipse运行为Java应用程序,而不是通过控制台> 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的Hibernate JPA(因此< tx:annotation-driven />) - 并且不会受到我使用的两个数据库的阻碍,它在Eclipse中运行时工作正常。
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:
@Component
public class TestRunner {
@Autowired
Handler handler;
public void run() {
handler.doTest();
}
}
TestHandler.java(groupId和groupName将在稍后阶段设置):
@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:
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDAO userDAO;
@Override
public List<User> loadUsersByGroupId(long id) {
return userDAO.findAllByGroupId(id);
}
...
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,使用两个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文件的其他框架的任何提示吗?
答案 0 :(得分:1)
如果它是从eclipse运行而不是从导出的jar文件运行,则导出出现问题
在导出窗口中有一个复选框Add directory entries
,应该检查组件扫描是否正常工作
答案 1 :(得分:1)
当你在Eclipse中运行它时,所有Spring依赖项和其他依赖项都被加载到你的类路径中,但是当你将应用程序导出为jar时,只会导出你的类,而不是依赖类。
通常有两种方法可以实现一个立式罐子。您可以创建一个'超级jar'(请参阅Is it possible to create an "uber" jar containing the project classes and the project dependencies as jars with a custom manifest file?),其中所有依赖jar都扩展为一个jar。然而,这种方法可能存在风险,因为如果罐子具有相同的文件名(例如:META-INF内的相同配置文件),它们可以相互覆盖
另一个更合适的方法是使用maven-dependency-plugin(请参阅dependency:copy)将所有依赖项复制到文件夹“dependencies”中。然后用
运行你的jarjava -cp "myjar.jar;dependencies/*" org.mycompany.MainClass
这不是一个独立的jar,而是一个独立的文件夹。缺点是每次添加/删除依赖项(例如:来自maven),你必须对依赖项文件夹执行相同的操作