Spring的注解和注入问题

影非弦 发布于 2015/01/15 15:51
阅读 4K+
收藏 1

spring提供的三种注入方式:设置注入、构造注入、注解注入

先上spring的配置文件:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       		http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-2.5.xsd
            http://www.springframework.org/schema/tx 
            http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
	        http://www.springframework.org/schema/aop 
	        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
	        
	<!-- 打开aop自动扫描管理器 -->
	<aop:aspectj-autoproxy/>
	<!-- 打开组件自动扫描管理器 --><!-- 扫描cn.zzbj下的组件 -->
    <context:component-scan base-package="cn.zzbj"/>
	<context:property-placeholder location="classpath:jdbc.properties"/>
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${driverClassName}"/>
		<property name="url" value="${url}"/>
		<property name="username" value="${username}"/>
		<property name="password" value="${password}"/>
		
		<!-- 连接池启动时的初始值 -->
		<property name="initialSize" value="${initialSize}"/>
		<!-- 连接池的最大值 -->
		<property name="maxActive" value="${maxActive}"/>
		<!-- 最大空闲值,当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
		<property name="maxIdle" value="${maxIdle}"/>
		<!-- 最小空闲值,当空闲的连接数少于阀值时,连接池就会预申请一些连接,以免高峰期来不及申请 -->
		<property name="minIdle" value="${minIdle}"/>
	</bean>
	<!-- 声明定义事务管理器 -->
	<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"/>
	</bean>
	<!-- 打开事物管理器注解标签 -->
	<tx:annotation-driven transaction-manager="txManager"/>
</beans>



业务bean:
package cn.zzbj.service.impl;

import java.util.List;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cn.zzbj.entity.Person;
import cn.zzbj.service.PersonService;

@Service("personService") @Scope("prototype") @Transactional
public class PersonServiceBean implements PersonService {
	private DataSource dataSource;
	private JdbcTemplate jdbcTemplate;
	
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}

	@Transactional(rollbackFor=Exception.class)
	@Override
	public void save(Person person) {
		System.out.println(jdbcTemplate==null);
		jdbcTemplate.update("insert into person(name) values(?)", new Object[]{person.getName()},
				new int[]{java.sql.Types.VARCHAR});
		//throw new RuntimeException();
	}

	@Transactional(rollbackFor=Exception.class)
	@Override
	public void update(Person person) {
		//测试datasource
		System.out.println(dataSource);
	}

	@Transactional(rollbackFor=Exception.class)
	@Override
	public void delete(Integer id) {
		// TODO Auto-generated method stub

	}

	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	@Override
	public Person getPerson(Integer id) {
		// TODO Auto-generated method stub
		return null;
	}

	@Transactional(propagation=Propagation.NOT_SUPPORTED)
	@Override
	public List<Person> getPersons() {
		// TODO Auto-generated method stub
		return null;
	}

}



测试方法:
@Test
	public void test() {
		ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
		PersonService ps = (PersonService) ac.getBean("personService");
		try {
			ps.update(new Person("aa"));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}



问:配置文件中已经有了dataSource的bean了,这里采用了setter注入方式,但是没有dataSource的值是null,如果给属性dataSource添加上@Resource注解结果就不为null,setter方法中加上this.dataSource=dataSource;结果还是一样为null。


而使用上述粘贴的代码测试save()方法的时候报错:

java.lang.NullPointerException

	at cn.zzbj.service.impl.PersonServiceBean.save(PersonServiceBean.java:31)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
	at com.sun.proxy.$Proxy11.save(Unknown Source)
	at cn.zzbj.test.ServiceTest.test(ServiceTest.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)



加载中
0
蔡熙伟
蔡熙伟
1.最初的配置是 service的属性 dataSource 不加 @Resource注解,结果dataSource为空容易理解,这就是一个普通属性,你么有初始化值
2.你在 dataSource属性上加注解@Resource ,那么就是初始话了dataSource,这时dataSource 不为空,但是dataSource有值不是调用 setDataSource方法的(你可以看你的方法setDataSource你是没有设置dataSource的传入值)
3.@Resource 注解是写在属性上,不是方法上的,所以写在方法上是没效的,所以dataSource为空
4.第二种方法的dataSource虽然不为空,但是这个service没有构造JdbcTemplate,因为@Resource注解没有调用setDataSource()方法




解决办法:
在xml配置该service 的bean,这样配置才会调用 setDataSource()方法初始化JdbcTemplate,(这时service的dataSource为空,因为你没有this.dataSource=dataSource)
初始化了JdbcTemplate,你调用save才不会报空异常


如果你是想使用注解方法,请将JdbcTemplate也当成是一个全局bean,使用@Resource调用,如果不是,每个service你都需要构造 或者加一个 BaseSservice, 所有service都继承
class class BaseSservice {
@Resource
private DataSource dataSource;


private JdbcTemplate jdbcTemplate;


@ModelAttribute
protected void initService() {
jdbcTemplate = new JdbcTemplate(this.dataSource);
}
}
0
wangyunzhong
wangyunzhong
@Service("personService") @Scope("prototype") @Transactional
public class PersonServiceBean implements PersonService {
    private DataSource dataSource;
    private JdbcTemplate jdbcTemplate;
     
    public void setDataSource(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }

这里只是说PersonServiceBean是一个需要spring管理的bean,bean的id为persionService。

bean为prototype方式管理。

bean有事物。

你也没有配置让spring给你注入datasoure啊。在datasource上添加注解,spring才会知道你需要注入这个属性。






影非弦
影非弦
恩,的确是这样,需要给加上注释
wangyunzhong
wangyunzhong
回复 @影非弦 : 下面的评论已经说得很详细了。spring不是通过有没有setter和getter方法来判断注入的。需要加额外的注解,spring才能知道。 没有setter和getter方法,配置正确的情况下,spring也可以注入。
影非弦
影非弦
这里有dataSource的setter方法啊,使用setter注入的。
0
小白白网
小白白网

Spring Injection with @Resource , @Autowired and @Inject

看看这个就明白了


http://www.zhanghenglei.com/spring-injection-with-resource-autowired-and-inject/

0
巴顿
巴顿

配置文件中已经有了dataSource的bean了,这里采用了setter注入方式。。。。

如果用setter方式的话,PersonServiceBean应该也配置在xml中,并且property其中一个为dataSource

要么全部用注解,要么全部用xml配置。不然出一堆问题搞死自己啊。

0
盲人摸象
盲人摸象
你set注入的方式你还没搞懂,不是有set方法  然后就可以自动注入。 其他人我没看,巴顿说的没错。
盲人摸象
盲人摸象
@影非弦 慢慢来
影非弦
影非弦
恩,有点混乱了
返回顶部
顶部