What's the difference between @Autowired and g

2019-04-28 16:00发布

问题:

I have a dao unit test that is declared as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class RegisterDaoTest extends AbstractTransactionalJUnit4SpringContextTests {

    ApplicationContext applicationContext = new     FileSystemXmlApplicationContext("classpath:/spring/applicationContext.xml");
    private IRegisterDao registerDao = applicationContext.getBean(IRegisterDao.class);

When I run the unit test, all pass and I can see the db getting recreated in between unit test executions.

My test db is defined as follows:

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    <property name="url" value="jdbc:hsqldb:mem:test;sql.syntax_ora=true;create=true"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
</bean>

<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
    <jdbc:script location="file:Artifacts/Hsql Version Scripts/install/droptables.sql" separator=";"/>
    <jdbc:script location="file:Artifacts/Hsql Version Scripts/install/install.sql" separator="/;"/>
</jdbc:initialize-database>

But when I change my test to use @Autowired, defined below, it does not execute the init db scripts.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/applicationContext.xml"})
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public class RegisterDaoTest extends AbstractTransactionalJUnit4SpringContextTests {

/*
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:/spring/applicationContext.xml");
    private IRegisterDao registerDao = applicationContext.getBean(IRegisterDao.class);
*/

    @Autowired
    private IRegisterDao registerDao;

I don't see what the difference is. I have two applicationContext.xmls, one in the main and one in the test (so I can override the db with the test db)

To me, it should execute the same. Am I missing something?

Thanks,

回答1:

By default, a Spring context will pay no attention to @Autowired annotations. In order to process them, the context needs to have a AutowiredAnnotationBeanPostProcessor bean registered in the context.

<context:annotation-config/>

registers one of these for you (along with a few others), so you do need it (unless you register AutowiredAnnotationBeanPostProcessor yourself, which is perfectly valid).

If you don't like having @Autowired in your code, then you can explicitly inject properties in the XML using , which just moves the clutter from one place to another.

If your context is extremely simple, then you can use implicit autowiring, as described here. Essentially, this tells Spring to autowire automatically by property name or type. This required very little configuration, but it very quickly gets out of control - it's automatic nature means it's hard to control, and gives you very little flexibility.

In general @Autowired really is the best option.

With application context, you are injecting the bean by yourself.

Annotation wiring isn’t turned on in the Spring container by default. So, before you can use annotation-based autowiring, you'll need to enable it in your Spring configuration. The simplest way to do that is with the

<context:annotation-config>
  <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
...
</beans>

Hope this helps.



回答2:

These two scenarios are very different: in the first case you've got TWO application contexts: one created by test spring framework and one created manually by you for each test. Spring test framework uses @ContextConfiguration to determine which context files are to be loaded. If subsequent tests use the same context files, the context is not recreated, it is reused. That's why your db is initialized only once if you don't additionally create a new context manually.

If you do need to reinitialize the db for each test, you should trigger it manually for example in @Before method. You may also try annotation @DirtiesContext on your test, next to @ContextConfiguration.

To make it clear: you should not create context manually if using spring test framework. @Autowired is the correct approach but you need to find other means to reinitialize your database before each test.