知识点:
为什么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 + "]";
}
}
数据库表:
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处.