spring加mybatis(Maven构建项目)简单篇---旨在探究spring配置方法和spring项目出现的异常分析


知识点:

为什么service和dao的实现类在上面写个注解,而service和dao的接口不要在上面配置注解呢?

因为注解是为了IOC,让spring来创建对象.spring创建对象是通过反射,一般是通过xxx.newInstance来创建的,所以应该要有一个无参构造函数,接口是没有的,

所以不会对一个接口实例化创建对象


怎么看编译生成的.class文件?

项目切换到Navigator, 在classes下存放的就是编译生成的.class文件


public interface SSOService {
	/**
	 * 注册用户
	 * @param user
	 * @throws Exception
	 */
	public void addUser(User user) throws Exception;
}
对应的class文件为:

// Compiled from SSOService.java (version 1.8 : 52.0, no super bit)
public abstract interface com.qx.sso.service.SSOService {
  
  // Method descriptor #6 (Lcom/qx/pojo/User;)V
  public abstract void addUser(com.qx.pojo.User arg0) throws java.lang.Exception;
}

可看到接口是没有构造方法的.


知识点2:

按类型自动注入: 既可以使用注解@Autowired 也可以使用 @Resource

@Service
public class SSOServiceImpl implements SSOService{
	
	//@Autowired
	@Resource
	private UserMapper UserMapper;

	@Override
	public void addUser(User user) throws Exception {
		// TODO Auto-generated method stub
		user.setUregistdate(new Date());
		UserMapper.addUser(user);
	}

}


------------------------------------------------------------------------------

@Service()
public class SSOServiceImpl implements SSOService{
	
	@Autowired
	private UserMapper UserMapper;

	@Override
	public void addUser(User user) throws Exception {
		// TODO Auto-generated method stub
		user.setUregistdate(new Date());
		UserMapper.addUser(user);
	}

}

对应的class文件为

// Compiled from SSOServiceImpl.java (version 1.8 : 52.0, super bit)
@org.springframework.stereotype.Service
public class com.qx.sso.service.impl.SSOServiceImpl implements com.qx.sso.service.SSOService {
  
  // Field descriptor #8 Lcom/qx/mapper/UserMapper;
  @org.springframework.beans.factory.annotation.Autowired
  private com.qx.mapper.UserMapper UserMapper;
  
  // Method descriptor #12 ()V
  // Stack: 1, Locals: 1
  public SSOServiceImpl();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [14]
    4  return
      Line numbers:
        [pc: 0, line: 13]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: com.qx.sso.service.impl.SSOServiceImpl
  
  // Method descriptor #21 (Lcom/qx/pojo/User;)V
  // Stack: 3, Locals: 2
  public void addUser(com.qx.pojo.User user) throws java.lang.Exception;
     0  aload_1 [user]
     1  new java.util.Date [25]
     4  dup
     5  invokespecial java.util.Date() [27]
     8  invokevirtual com.qx.pojo.User.setUregistdate(java.util.Date) : void [28]
    11  aload_0 [this]
    12  getfield com.qx.sso.service.impl.SSOServiceImpl.UserMapper : com.qx.mapper.UserMapper [34]
    15  aload_1 [user]
    16  invokeinterface com.qx.mapper.UserMapper.addUser(com.qx.pojo.User) : void [36] [nargs: 2]
    21  return
      Line numbers:
        [pc: 0, line: 21]
        [pc: 11, line: 22]
        [pc: 21, line: 23]
      Local variable table:
        [pc: 0, pc: 22] local: this index: 0 type: com.qx.sso.service.impl.SSOServiceImpl
        [pc: 0, pc: 22] local: user index: 1 type: com.qx.pojo.User

}


---------------------------------------------------------------------------------------------------------------------------------------

项目结构:


配置文件:

db.properties:

jdbc.url=jdbc:mysql:///yirenbao?characterEncoding=utf-8
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root

mybaits.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
			<plugins>
			<!-- 
			3.4.2版本pagehelper
			<plugin interceptor="com.github.pagehelper.PageHelper">
				<property name="dialect" value="mysql"/>
			</plugin>
			 -->
			 <!--5.0版本pagehelper -->
			<plugin interceptor="com.github.pagehelper.PageInterceptor">
				<property name="helperDialect" value="mysql"/>
			</plugin>
			
	</plugins>
</configuration>

applicationContext.xml:

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


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

applicationContext-dao.xml

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 数据库连接相关信息配置 -->
	<!-- 导入数据库配置文件 -->
	<context:property-placeholder location="classpath*:conf/db.properties"/>
	
	<!-- dataSource -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	
	<!-- 配置工厂 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="configLocation" value="classpath:mybatis/mybatis.xml"></property>
	</bean>
	
	<!-- 配置扫描mapper文件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.qx.mapper"></property>
	</bean>
</beans>




applicationContext-tran.xml

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 事务管理器 -->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean> 
	
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<!-- 约定优于编码 设置事务详情  -->
			<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
			<tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
			<tx:method name="select*" read-only="true" propagation="SUPPORTS"/>
			<tx:method name="add*"/>
			<tx:method name="save*"/>
			<tx:method name="insert*"/>
			<tx:method name="delete*"/>
			<tx:method name="update*"/>
		</tx:attributes>
	</tx:advice>
	
	<aop:config>
		<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.qx..service..*.*(..))"/>
	</aop:config>
</beans>




web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <display-name>yirenbao</display-name>
  	<context-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath*:spring/app*.xml</param-value>
  	</context-param>
 	<listener>
 		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 	</listener>
 	
 	<servlet>
 		<servlet-name>SpringMVC</servlet-name>
 		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 		<init-param>
 			<param-name>contextConfigLocation</param-name>
 			<param-value>classpath*:spring/spring-MVC.xml</param-value>
 		</init-param>
 		<load-on-startup>2</load-on-startup>
 	</servlet>
 	<servlet-mapping>
 		<servlet-name>SpringMVC</servlet-name>
 		<url-pattern>*.action</url-pattern>
 	</servlet-mapping>
</web-app>


User:

package com.qx.pojo;

import java.util.Date;

/**
 * 用户类
 * @author dell
 *
 */
public class User {
	private Integer uid;
	private String unickname;
	private String upassword;
	private String uphonenumber;
	private String ureferrer;
	private Date uregistdate;
	private String uheadimg;
	private String ulastip;
	private Date ulasttime;
	public Integer getUid() {
		return uid;
	}
	public void setUid(Integer uid) {
		this.uid = uid;
	}
	public String getUnickname() {
		return unickname;
	}
	public void setUnickname(String unickname) {
		this.unickname = unickname;
	}
	public String getUpassword() {
		return upassword;
	}
	public void setUpassword(String upassword) {
		this.upassword = upassword;
	}
	public String getUphonenumber() {
		return uphonenumber;
	}
	public void setUphonenumber(String uphonenumber) {
		this.uphonenumber = uphonenumber;
	}
	public String getUreferrer() {
		return ureferrer;
	}
	public void setUreferrer(String ureferrer) {
		this.ureferrer = ureferrer;
	}
	public Date getUregistdate() {
		return uregistdate;
	}
	public void setUregistdate(Date uregistdate) {
		this.uregistdate = uregistdate;
	}
	public String getUheadimg() {
		return uheadimg;
	}
	public void setUheadimg(String uheadimg) {
		this.uheadimg = uheadimg;
	}
	public String getUlastip() {
		return ulastip;
	}
	public void setUlastip(String ulastip) {
		this.ulastip = ulastip;
	}
	public Date getUlasttime() {
		return ulasttime;
	}
	public void setUlasttime(Date ulasttime) {
		this.ulasttime = ulasttime;
	}
	@Override
	public String toString() {
		return "User [uid=" + uid + ", unickname=" + unickname + ", upassword=" + upassword + ", uphonenumber="
				+ uphonenumber + ", ureferrer=" + ureferrer + ", uregistdate=" + uregistdate + ", uheadimg=" + uheadimg
				+ ", ulastip=" + ulastip + ", ulasttime=" + ulasttime + "]";
	}
	
}


数据库表:



UserMapper接口

package com.qx.mapper;

import com.qx.pojo.User;

public interface UserMapper {
	
	/**
	 * 注册
	 * @param user
	 */
	public void addUser(User user);
}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.qx.mapper.UserMapper">
	
	<insert id="addUser" parameterType="com.qx.pojo.User">
		<!-- 是否需要获取插入后的主键id -->
		<selectKey keyProperty="uid" resultType="integer" order="AFTER">
			select last_insert_id()
		</selectKey>
		insert into users (unickname,upassword,uphonenumber,ureferrer,uregistdate,uheadimg,ulastip,ulasttime)
		values (#{unickname},#{upassword},#{uphonenumber},#{ureferrer},#{uregistdate},#{uheadimg},#{ulastip},#{ulasttime})
	</insert>
</mapper>


SSOService接口

package com.qx.sso.service;

import com.qx.pojo.User;

public interface SSOService {
	/**
	 * 注册用户
	 * @param user
	 * @throws Exception
	 */
	public void addUser(User user) throws Exception;
}


SSOServiceImpl:

package com.qx.sso.service.impl;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.qx.mapper.UserMapper;
import com.qx.pojo.User;
import com.qx.sso.service.SSOService;

@Service()  // 也可以不要括号,直接写为 @Service
public class SSOServiceImpl implements SSOService{
	
	@Autowired
	private UserMapper UserMapper;

	@Override
	public void addUser(User user) throws Exception {
		// TODO Auto-generated method stub
		user.setUregistdate(new Date());
		UserMapper.addUser(user);
	}

}


测试类:SSOTest

package com.qx.test;

import java.util.Date;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.qx.pojo.User;
import com.qx.sso.service.SSOService;
import com.qx.sso.service.impl.SSOServiceImpl;

public class SSOTest {
	
	@Test
	public void test() throws Exception {
		ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/app*.xml");
		SSOService ssoService=context.getBean(SSOService.class);
		User user=new User();
		user.setUnickname("tingjie");
		user.setUpassword("000111");
		user.setUphonenumber("13173278989");
		user.setUregistdate(new Date());
		ssoService.addUser(user);
	}
}


运行测试类:

插入数据成功


注意点1:


如果将

SSOService ssoService=context.getBean(SSOService.class);
改成

SSOService ssoService=context.getBean(SSOServiceImpl.class);

则出现异常:




注意点2:

如果将@Service 注解写在了接口SSOService上,而不是实现类上, 也将报与注意点一同样的异常


下面是错误的:

@Service()
public interface SSOService {
	/**
	 * 注册用户
	 * @param user
	 * @throws Exception
	 */
	public void addUser(User user) throws Exception;
}




注意点3:

也可以使用context.getBean(String beanId)  ,此时需采用另一种实例化接口类对象的方式:

在applicationContext.xml中添加bean:

<bean id="sSOService" class="com.qx.sso.service.impl.SSOServiceImpl"></bean>

即:

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">


	<context:component-scan base-package="com.qx"></context:component-scan>
	
	<bean id="sSOService" class="com.qx.sso.service.impl.SSOServiceImpl"></bean>
</beans>


去掉Service层,实现类SSOServiceImpl 的注解@Service


测试类中:使用context.getBean(String beanId)



注意点4:

spring+mybatis ;  在持久化类上不用加任何注解


注意点5:

不能即在spring配置文件中配置

<bean id="sSOService" class="com.qx.sso.service.impl.SSOServiceImpl"></bean>

又在Service层给服务实现类加@Service注解

@Service
public class SSOServiceImpl implements SSOService{
	
	@Autowired
	private UserMapper UserMapper;

	@Override
	public void addUser(User user) throws Exception {
		// TODO Auto-generated method stub
		user.setUregistdate(new Date());
		UserMapper.addUser(user);
	}

}

否则运行下面测试类会报错:

public class SSOTest {
	
	@Test
	public void test() throws Exception {
		ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/app*.xml");
		SSOService ssoService=context.getBean(SSOService.class);
		User user=new User();
		user.setUnickname("tingjie");
		user.setUpassword("000111");
		user.setUphonenumber("13173278989");
		user.setUregistdate(new Date());
		ssoService.addUser(user);
	}
}

错误:

NoUniqueBeanDefinitionException  ,本来需要唯一的对象,但现在在getBean时出问题了,有两个对象都匹配,它也不知道选择谁了.

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.qx.sso.service.SSOService' available: expected single matching bean but found 2: SSOServiceImpl,sSOService
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
    at com.qx.test.SSOTest.test(SSOTest.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    ....................................................................

    ....................................................................


注意点6:

getBean(Class<T> requiredType) 方法传入的参数类对象,必须是接口或父类.(也暗含着另一层含义,不能是接口实现类类对象)

,者就说明了注意点1提到的传入类对象SSOserviceImpl.class,运行时会报错, 传入类对象SSOservice.class运行时不会报错的原因.



注意点7:

扫描mapper的那个配置,配置不当会出异常

将在applicationContext-dao.xml中配值的

	<!-- 配置扫描mapper文件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.qx.mapper"></property>
	</bean>

改为

	<!-- 配置扫描mapper文件 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.qx"></property>
	</bean>

则再次运行测试类方法就会出现异常:

测试类方法:

	@Test
	public void test() throws Exception {
		ApplicationContext context=new ClassPathXmlApplicationContext("classpath:spring/app*.xml");
		SSOService ssoService=context.getBean(SSOService.class);
		User user=new User();
		user.setUnickname("tingjie");
		user.setUpassword("000111");
		user.setUphonenumber("13173278989");
		user.setUregistdate(new Date());
		ssoService.addUser(user);
	}

运行时,异常信息:

会发现又是这个异常:NoUniqueBeanDefinitionException

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.qx.sso.service.SSOService' available: expected single matching bean but found 2: SSOServiceImpl,SSOService
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
    at com.qx.test.SSOTest.test(SSOTest.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    .........................................................................................

    ........................................................................................


原因分析:

先看下项目目录结构注意包com.qx



在com.qx下有两个接口:UserMapper和SSOService, 

因此配置为

    <!-- 配置扫描mapper文件 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.qx"></property>
    </bean>

指定在com.qx下去扫描mapper文件

mapper包里面都是接口,只要是接口,就能被mybatis认为这是一个操作数据库的文件,它就会干一件事,生成动态代理对象. 因此扫基础包com.qx,就会包基础包里的接口SSOService当成一个mapper文件,把它当成一个mapper,就会创建一个动态代理对象,这样就有一个这样类型的对象了.

再加上通过@Service注解创建的对象,这样一来,就有两个对象了:

一个是mybatis把它当成mapper生成的动态代理类对象,一个是它的实现类对象,它不知道该注入谁了



注意点8:

若在applicationContext.xml中取消 组件扫描,

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

其他不做任何改变,则运行测试类测试方法时会报异常:在getBean处.




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值