Spring是基于javaEE应用一站式轻量级开源框架,主要核心是IOC(控制反转/依赖注入)和AOP(面向切面编程)两大技术,实现项目在开发过程中轻松解耦,提高开发效率。
项目引入Spring可以降低组件之间的耦合度,实现软件各层之间的解耦。可以使用容器提供的众多服务,比如事务管理、消息服务等。容器提供了AOP技术,可以很容易实现如权限拦截、运行期监控等功能。
Spring组件被整合在核心容器(core Container)、Aop(Aspect Oriented Programming)和设备支持(Instrmentation)、数据访问及集成(Data Access/Integeration)、Web、报文发送(Messaging)、测试6个模块集合中。
pom.xml
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.14version>
dependency>
package com.xxxx.service;
public class UserService {
public void test(){
System.out.println("UserService test...");
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="..." class="...">
bean>
<bean id="..." class="...">
bean>
beans>
<bean id="userService" class="com.xxxx.service.UserService">
bean>
<bean id="userService02" class="com.xxxx.service.UserService02">
bean>
package com.xxxx.test;
import com.xxxx.service.UserService;
import com.xxxx.service.UserService02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter01 {
public static void main(String []args){
//等到Spring的上下文环境
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//通过id属性值得到指定的Bean对象
UserService userService=(UserService) ac.getBean("userService");
UserService02 userService02=(UserService02)ac.getBean("userService02");
//调用实例化好的JavaBean对象中的方法
userService.test();
userService02.test();
}
}
用来接收配置文件中bean标签的id与class属性值
package com.xxxx.spring;
/**
* 用来接收配置文件中bean标签的id与class属性值
*/
public class MyBean {
private String id;//bean对象的id属性值
private String clazz;//bean对象的类路径
public MyBean(String id, String clazz) {
this.id = id;
this.clazz = clazz;
}
public MyBean() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}
<dependency>
<groupId>dom4jgroupId>
<artifactId>dom4jartifactId>
<version>1.1version>
dependency>
<dependency>
<groupId>jaxengroupId>
<artifactId>jaxenartifactId>
<version>1.1.6version>
dependency>
spring.xml
<beans>
<bean id="userDao" class="com.xxxx.dao.UserDao">bean>
<bean id="userService" class="com.xxxx.service.userService">bean>
beans>
package com.xxxx.spring;
/**
* 定义Bean工厂接口
*/
public interface MyFactory {
//通过id值获取对象
public Object getBean(String id);
}
package com.xxxx.spring;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 模拟spring实现:
* 1.通过构造器得到相关配置文件
* 2.通过dom4j解析xml文件,得到List集合,存放id和class属性值
* 3.通过反射实例化得到对象,通过Map存储。(遍历list集合,通过获取对应的class属性,利用Class.forName(类的全路径).newInstance())
* 4.通过id属性值得到指定的实例化对象
*/
public class MyClassPathXmlApplicationContext implements MyFactory{
private Map<String,Object> beanMap=new HashMap<>();//存放实例化后的对象,通过id获取对应的对象
private List<MyBean> beanList;//存放从配置文件获取到的bean标签的信息
//1.通过构造器得到相关配置文件
public MyClassPathXmlApplicationContext(String fileName){
//2.通过dom4j解析xml文件,得到list,存放id和class
this.parseXml(fileName);
//3.通过反射实例化得到对象 Class.forName(类的全路径).newInstance();通过Map存储
this.instanceBean();
}
/**
* 通过dom4j解析xml文件,得到list,存放id和class
* 1.获取解析器
* 2.得到配置文件的URL
* 3.通过解析器解析xml文件(Spring.xml)
* 4.通过xPath语法,获取beans标签下的所有bean标签
* 5.通过指定语法解析文档对象,返回集合
* 6.判断集合是否为空,遍历集合
* 7.获取标签元素的属性
* 8.得到Bean对象,将Bean对象设置到集合中
* @param fileName
*/
private void parseXml(String fileName) {
// 1.获取解析器
SAXReader reader=new SAXReader();
// 2.得到配置文件的URL
URL url=this.getClass().getClassLoader().getResource(fileName);
// 3.通过解析器解析xml文件(Spring.xml)
try{
//3.通过解析器解析xml文件(Spring.xml)
Document document=reader.read(url);
// 4.通过xPath语法,获取beans标签下的所有bean标签
XPath xPath=document.createXPath("beans/bean");
// 5.通过指定语法解析文档对象,返回集合
List<Element> elementList=xPath.selectNodes(document);
// 6.判断集合是否为空,遍历集合
if(elementList!=null&&elementList.size()>0){
beanList=new ArrayList<>();
for(Element el:elementList){
// 7.获取标签元素的属性
String id=el.attributeValue("id");
String clazz=el.attributeValue("class");
//System.out.println("id: "+id);
//System.out.println("class: "+clazz);
// 8.得到Bean对象,将Bean对象设置到beanList集合中
MyBean bean=new MyBean(id,clazz);
beanList.add(bean);
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 通过反射实例化得到对象
* Class.forName(类的全路径).newInstance();
* 通过Map存储
*/
private void instanceBean() {
//1.判断beanList集合是否为空,不为空则遍历得到Bean对象
if(beanList!=null&&beanList.size()>0){
for(MyBean bean:beanList){
String id=bean.getId();
String clazz= bean.getClazz();
try{
//通过全路径名 反射 实例化对象
Object object=Class.forName(clazz).newInstance();
//将id与实例化对象设置到map对象中
beanMap.put(id,object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
/**
* 通过key获取map中指定的value
* @param id
* @return
*/
@Override
public Object getBean(String id) {
Object object=beanMap.get(id);
return object;
}
}
package com.xxxx.service;
public class UserService {
public void testService(){
System.out.println("test Service ...");
}
}
UserDao.java
package com.xxxx.dao;
public class UserDao {
public void testDao(){
System.out.println("test dao...");
}
}
package com.xxxx;
import com.xxxx.dao.UserDao;
import com.xxxx.service.UserService;
import com.xxxx.spring.MyClassPathXmlApplicationContext;
import com.xxxx.spring.MyFactory;
/**
* Hello world!
* */
public class App
{
public static void main( String[] args ) {
//得到工厂的实现对象
MyFactory factory=new MyClassPathXmlApplicationContext("spring.xml");
//得到对应的实例化对象
UserDao userDao=(UserDao) factory.getBean("userDao");
userDao.testDao();
UserService userService=(UserService) factory.getBean("userService");
userService.testService();
}
}
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.xxxx.service.UserService">bean>
根据相对路径加载资源:
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
根据绝对路径加载资源:
ApplicationContext ac=new FileSystemXmlApplicationContext("C:\Users\17208\IdeaProjects\spring03\src\main\resources\spring.xml");
Spring框架启动时可以加载多个配置文件到环境中,项目在启动部署时会将多个配置文件同时加载出来。
service.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.xxxx.service.UserService">bean>
dao.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.xxxx.service.UserDao">bean>
//同时加载多个资源文件
ApplicationContext ac=new ClassPathXmlApplicationContext("service.xml","dao.xml");
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="service.xml"/>
<import resource="dao.xml"/>
beans>
加载时只需要加载总的配置文件即可:
//加载总的资源文件
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
通过默认构造器创建,空构造方法必须存在,否则会创建失败。
可能产生循环依赖问题,如果产生问题,使用Set注入。
设置配置文件spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService" class="com.xxxx.service.UserService">bean>
beans>
获取实例化对象
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
注意:
package com.xxxx.factory;
import com.xxxx.dao.UserDao03;
/**
* 静态工厂
*/
public class StaticFactory {
/**
* 定义静态方法,返回实例化对象
* @return
*/
public static UserDao03 createTypeDao(){
return new UserDao03();
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao03" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao">bean>
ApplicationContext ac=new ClassPathXmlApplicationContext("spring03.xml");
UserService03 userService03= (UserService03) ac.getBean("userService03");
userService03.test();
Spring先解析配置文件,并根据配置文件指定信息,通过反射调用静态工厂类的静态工厂方法,将该静态工厂方法返回值作为Bean实例,该过程中Spring不负责创建Bean实例,而是由用户提供的静态工厂方法创建实例。
注意:
package com.xxxx.factory;
import com.xxxx.dao.UserDao03;
public class InstanceFactory {
public UserDao03 createUserDao03(){
return new UserDao03();
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory">bean>
<bean id="userDao03" factory-bean="instanceFactory" factory-method="createUserDao03">bean>
beans>
ApplicationContext ac=new ClassPathXmlApplicationContext("spring03.xml");
UserService03 userService03= (UserService03) ac.getBean("userService03");
userService03.test();
一般选择set方式注入
注:
业务对象JavaBean:
public class UserService {
//业务逻辑对象 JavaBean对象 set方法注入
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.xxxx.dao.UserDao">bean>
<bean id="studentDao" class="com.xxxx.dao.StudentDao">bean>
<bean id="userService" class="com.xxxx.service.UserService">
<property name="userDao" ref="userDao"/>
<property name="studentDao" ref="studentDao"/>
<property name="host" value="127.0.0.1"/>
<property name="port" value="8080"/>
<property name="list">
<list>
<value>上海value>
<value>北京value>
<value>杭州value>
list>
property>
<property name="map">
<map>
<entry>
<key><value>Chinavalue>key>
<value>中国value>
entry>
<entry>
<key><value>frencvalue>key>
<value>法国value>
entry>
map>
property>
<property name="properties">
<props>
<prop key="1">oneprop>
<prop key="2">twoprop>
<prop key="3">threeprop>
props>
property>
bean>
beans>
UserService .java
package com.xxxx.service;
import com.xxxx.dao.StudentDao;
import com.xxxx.dao.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Set方法注入:
* 1.属性字段提供set方法
* 2.在配置文件中通过property属性指定属性字段
*/
public class UserService {
//手动实例化
//private UserDao userDao=new UserDao();
//业务逻辑对象 JavaBean对象 set方法注入
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
//JavaBean对象
private StudentDao studentDao;
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
//常用类型
private String host;
public void setHost(String host) {
this.host = host;
}
//基本类型
private Integer port;
public void setPort(Integer port) {
this.port = port;
}
//List集合
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void printList(){
for(String s:list){
System.out.print(s+" ");
}
System.out.println("");
}
//Map集合
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
public void printMap(){
System.out.println(map.toString());
}
//properties集合
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void printProperties(){
System.out.println(properties.toString());
}
public void test(){
System.out.println("UserService test...");
userDao.test();
studentDao.test();
System.out.println(host);
System.out.println(port);
printList();
printMap();
printProperties();
}
}
Starter01.java(测试)
package com.xxxx.test;
import com.xxxx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter01 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
}
}
注意:需要提供带参构造。
UserService02.java
package com.xxxx.service;
import com.xxxx.dao.StudentDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDao02;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 构造器注入
* 需要提供带参构造
* 可能产生循环依赖问题,如果产生问题,使用Set注入
*/
public class UserService02 {
private UserDao02 userDao02;
/*public UserService02(UserDao02 userDao02){
this.userDao02=userDao02;
}*/
private StudentDao studentDao;
public UserService02(UserDao02 userDao02,StudentDao studentDao){
this.userDao02=userDao02;
this.studentDao=studentDao;
}
public void test(){
System.out.println("UserService02 test...");
userDao02.test();
studentDao.test();
}
}
spring02.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService02" class="com.xxxx.service.UserService02">
<constructor-arg name="userDao02" ref="userDao02">constructor-arg>
<constructor-arg name="studentDao" ref="studentDao">constructor-arg>
bean>
<bean id="userDao02" class="com.xxxx.dao.UserDao02">bean>
<bean id="studentDao" class="com.xxxx.dao.StudentDao">bean>
beans>
Starter02.java
package com.xxxx.test;
import com.xxxx.service.UserService02;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter02 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");
UserService02 userService02= (UserService02) ac.getBean("userService02");
userService02.test();
}
}
StaticFactory.java
package com.xxxx.factory;
import com.xxxx.dao.UserDao03;
/**
* 静态工厂
*/
public class StaticFactory {
/**
* 定义静态方法,返回实例化对象
* @return
*/
public static UserDao03 createTypeDao(){
return new UserDao03();
}
}
UserService03.java
package com.xxxx.service;
import com.xxxx.dao.StudentDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDao03;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class UserService03 {
private UserDao03 userDao03;
public void setUserDao03(UserDao03 userDao03){
this.userDao03=userDao03;
}
public void test(){
System.out.println("UserService03 test...");
userDao03.test();
}
}
spring03.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService03" class="com.xxxx.service.UserService03">
<property name="userDao03" ref="userDao03">property>
bean>
<bean id="userDao03" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao">bean>
beans>
Starter03.java
package com.xxxx.test;
import com.xxxx.service.UserService03;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter03 {
public static void main(String[] args) {
System.out.println("静态工厂实例化");
ApplicationContext ac=new ClassPathXmlApplicationContext("spring03.xml");
UserService03 userService03= (UserService03) ac.getBean("userService03");
userService03.test();
}
}
InstanceFactory.java
package com.xxxx.factory;
import com.xxxx.dao.UserDao03;
public class InstanceFactory {
public UserDao03 createUserDao03(){
return new UserDao03();
}
}
spring03.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userService03" class="com.xxxx.service.UserService03">
<property name="userDao03" ref="userDao03">property>
bean>
<bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory">bean>
<bean id="userDao03" factory-bean="instanceFactory" factory-method="createUserDao03">bean>
beans>
UserService03.java
package com.xxxx.service;
import com.xxxx.dao.StudentDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDao03;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class UserService03 {
private UserDao03 userDao03;
public void setUserDao03(UserDao03 userDao03){
this.userDao03=userDao03;
}
public void test(){
System.out.println("UserService03 test...");
userDao03.test();
}
}
Starter03.java
package com.xxxx.test;
import com.xxxx.service.UserService03;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter03 {
public static void main(String[] args) {
System.out.println("实例化工厂实例化");
ApplicationContext ac=new ClassPathXmlApplicationContext("spring03.xml");
UserService03 userService03= (UserService03) ac.getBean("userService03");
userService03.test();
}
}
package com.xxxx.service;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDao03;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* p名称空间的使用
*/
public class UserService04 {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
private String host;
public void setHost(String host) {
this.host = host;
}
public void test(){
System.out.println("UserService04 test...");
userDao.test();
System.out.println(host);
}
}
xmlns:p="http://www.springframework.org/schema/p"
spring04.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userDao" class="com.xxxx.dao.UserDao">bean>
<bean id="userService04" class="com.xxxx.service.UserService04"
p:host="127.0.0.1"
p:userDao-ref="userDao">
bean>
beans>
Starter04.java
package com.xxxx.test;
import com.xxxx.service.UserService04;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Starter04 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring04.xml");
UserService04 userService04= (UserService04) ac.getBean("userService04");
userService04.test();
}
}
注解方式注入Bean,可以简化配置文件,提高开发速度,使程序看上去更简洁。通过反射技术实现。
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
beans>
<context:annotation-config/>
<bean id="userDao" class="com.xxxx.dao.UserDao">bean>
<bean id="userService" class="com.xxxx.service.UserService">bean>
在需要被实例化的Bean的类上添加指定的注解,注解声明在类级别
(Bean对象的id属性默认为类的首字母小写)
@Repository(Dao层)
@Service(Service层)
@Controller(Controller层)
@Component(任意层)
package com.xxxx.service;
import com.xxxx.dao.UserDao;
import javax.annotation.Resource;
public class UserService {
@Resource
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void test(){
System.out.println("UserService test...");
userDao.test();
}
}
package com.xxxx.dao;
public interface IUserDao {
public void test();
}
UserDao.java
package com.xxxx.dao;
public class UserDao implements IUserDao{
public void test(){
System.out.println("UserDao test...");
}
}
UserDaoImplement01.java
package com.xxxx.dao;
public class UserDaoImplement01 implements IUserDao{
@Override
public void test() {
System.out.println("IUserDao test...\nUserDaoImplement01 test...");
}
}
UserService.java
package com.xxxx.service;
import com.xxxx.dao.IUserDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDaoImplement01;
import javax.annotation.Resource;
/**
* @Resource注解实现自动注入(反射)
* 1.注解默认通过属性字段名称查找对应bean对象(属性字段名称与bean标签的id属性值一致)
* 2.如果属性字段名称不一样,则会通过类型(class)类型
* 3.属性字段可以提供set方法,也可不提供
* 4.注解可以声明在属性字段上,或set方法级别
* 5.可以设置注解的name属性,name属性值要与bean标签的id属性值一致,如果设置了name属性,则需要使用name属性查找bean对象 @Resource(name="userDao")
* 6.注入接口时,如果接口只有一个实现类,则正常实例化,如有多个实现类,则需要使用name属性指定需要被实例化的bean对象
*/
public class UserService {
@Resource
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Resource(name="userDaoImplement01")
private IUserDao iUserDao;
public void test(){
System.out.println("UserService test...");
userDao.test();
iUserDao.test();
}
}
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="userDao" class="com.xxxx.dao.UserDao">bean>
<bean id="userService" class="com.xxxx.service.UserService">bean>
<bean id="userDaoImplement01" class="com.xxxx.dao.UserDaoImplement01">bean>
beans>
Start01.java
package com.xxxx.test;
import com.xxxx.service.AccountService;
import com.xxxx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.applet.AppletContext;
public class Starter01 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService=(UserService) ac.getBean("userService");
userService.test();
// AccountService accountService=(AccountService) ac.getBean("accountService");
// accountService.test();
}
}
package com.xxxx.dao;
public class AccountDao {
public void test(){
System.out.println("AccountDao test...");
}
}
UserDaoImplement01.java
package com.xxxx.dao;
public class UserDaoImplement01 implements IUserDao{
@Override
public void test() {
System.out.println("UserDaoImplement01 test...");
}
}
AccountService.java
package com.xxxx.service;
import com.xxxx.dao.AccountDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDaoImplement01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.annotation.Resource;
/**
* @Autowired注解实现自动注入
* 1.注解默认通过类型(class)类型查找对应bean对象(与属性字段名称无关)
* 2.属性字段可以提供set方法,也可不提供
* 3.注解可以声明在属性字段上,或set方法级别
* 4.如果需要通过指定id名称查找bean对象,需要结合@Qualifier(value="accountDao")设定value属性值
*/
public class AccountService {
@Autowired
@Qualifier(value="accountDao")
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Resource(name="userDaoImplement01")
private UserDaoImplement01 userDaoImplement01;
public void test(){
System.out.println("UserService test...");
accountDao.test();
userDaoImplement01.test();
}
}
spring.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="userDaoImplement01" class="com.xxxx.dao.UserDaoImplement01">bean>
<bean id="accountDao" class="com.xxxx.dao.AccountDao">bean>
<bean id="accountService" class="com.xxxx.service.AccountService">bean>
beans>
扫描器对扫描到的对象统一进行管理,简化开发配置,提高开发效率。
<context:component-scan base-package="扫描范围"/>
spring.xml
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xxxx"/>
beans>
TypeDao.java( Dao层) @Repository
package com.xxxx.dao;
import org.springframework.stereotype.Repository;
@Repository
public class TypeDao {
public void test(){
System.out.println("TypeDao test...");
}
}
TypeService.java(service层) @Service
package com.xxxx.service;
import com.xxxx.dao.TypeDao;
import com.xxxx.dao.UserDao;
import com.xxxx.dao.UserDaoImplement01;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class TypeService {
@Resource
private TypeDao typeDao;
public void test(){
System.out.println("TypeService test...");
typeDao.test();
}
}
TypeController.java(controller层) @Controller
package com.xxxx.controller;
import com.xxxx.service.TypeService;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
@Controller
public class TypeController {
@Resource
private TypeService typeService;
public void test(){
System.out.println("TypeController test...");
typeService.test();
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.xxxxgroupId>
<artifactId>myLoginSpringartifactId>
<version>1.0-SNAPSHOTversion>
<name>myLoginSpringname>
<url>http://www.example.comurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.14version>
dependency>
dependencies>
<build>
build>
project>
spring.xml(Spring IOC配置)
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xxxx"/>
beans>
StringUtil.java(字符串工具类)
package com.xxxx.util;
/**
* 字符串工具类
*/
public class StringUtil {
/**
* 判断字符串是否为空
* 为空返回true,非空返回false
* @param str
* @return
*/
public static boolean isEmpty(String str){
if(str==null||"".equals(str.trim())){
return true;
}
return false;
}
}
User.java(用户实体类)
package com.xxxx.entity;
/**
* User 用户实体类
*/
public class User {
private String userName;
private String userPwd;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
}
MessageModel.java(消息模型类,用来接收处理结果)
package com.xxxx.entity.vo;
/**
* 消息模型对象,用来接收处理结果
*/
public class MessageModel {
private Integer resultCode=1;//1=成功,0=失败
private String resultMsg;//提示信息
public Integer getResultCode() {
return resultCode;
}
public void setResultCode(Integer resultCode) {
this.resultCode = resultCode;
}
public String getResultMsg() {
return resultMsg;
}
public void setResultMsg(String resultMsg) {
this.resultMsg = resultMsg;
}
}
UserDao.java(数据库操作。查询用户对象)
package com.xxxx.dao;
import com.xxxx.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
//定义登录账号密码
private final String USERNAME="admin";
private final String USERPWD="admin";
/**
* 通过用户名查询用户对象
* 存在则返回对应用户
* 不存在则返回空对象
* @param userName
* @return
*/
public User queryUserByUserName(String userName){
User user=new User();
if(!USERNAME.equals(userName)){
return user;
}
user=new User();
user.setUserName(userName);
user.setUserPwd(USERPWD);
return user;
}
}
UserService.java(业务逻辑处理,调用Dao层。验证登录是否成功)
package com.xxxx.service;
import com.xxxx.dao.UserDao;
import com.xxxx.entity.User;
import com.xxxx.entity.vo.MessageModel;
import com.xxxx.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource
private UserDao userDao;
/**
* 验证登录是否成功
* 参数非空校验
* 通过用户名查询用户对象(调用dao层查询方法)
* 判断密码是否正确
* @param userName
* @param userPwd
* @return
*/
public MessageModel checkUserLogin(String userName,String userPwd){
MessageModel messageModel=new MessageModel();
//参数非空校验
if(StringUtil.isEmpty(userName)||StringUtil.isEmpty(userPwd)){
messageModel.setResultCode(0);
messageModel.setResultMsg("用户名和密码不能为空!");
return messageModel;
}
//通过用户名查询用户对象(调用dao层查询方法)
User user=userDao.queryUserByUserName(userName);
//判断用户对象是否为空
if(user==null){
messageModel.setResultCode(0);
messageModel.setResultMsg("用户名不存在!");
return messageModel;
}
//判断密码是否正确
if(!userPwd.equals(user.getUserPwd())){
messageModel.setResultCode(0);
messageModel.setResultMsg("密码不正确!");
return messageModel;
}
//登录成功
messageModel.setResultCode(1);
messageModel.setResultMsg("登录成功!");
return messageModel;
}
}
UserController.java(接收响应请求,调用Service层)
package com.xxxx.controller;
import com.xxxx.entity.vo.MessageModel;
import com.xxxx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
@Autowired
private UserService userService;
public MessageModel userLogin(String userName,String userPwd){
MessageModel messageModel=userService.checkUserLogin(userName,userPwd);
return messageModel;
}
}
UserTest.java(测试)
package com.xxxx.test;
import com.xxxx.controller.UserController;
import com.xxxx.entity.vo.MessageModel;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
public static void main(String[] args) {
try {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserController userController= (UserController) ac.getBean("userController");
MessageModel messageModel=userController.userLogin("d","admin");
System.out.println(messageModel.getResultMsg());
}catch (Exception e){
e.printStackTrace();
}
}
}
默认情况下,Spring容器中的对象是单例的。
bean的作用域类型如下:
容器在启动情况下就实例化所有singleton的bean对象,并缓存于容器中。
默认情况下,被管理的bean只会在IOC容器中存在一个实例,对于所有获取该bean的操作,容器返回同一个bean。
<bean id="bean" class="..." lazy-init="false">bean>
lazy-init=“false”:
什么对象适合作为单例对象?(适合交给IOC容器实例化):无状态对象,即不存在改变当前对象状态的成员变量(属性)的对象,比如Controller层、Service层、Dao层,而User实体类工具类等则不适合作为单例对象。这样保证了线程安全性。
<bean id="bean1" class="..." scope="prototype"/>
通过scope="prototype"设置,Spring容器不缓存bean实例化对象,每次向容器请求获取bean都会返回一个全新的bean。
配置方式和基本作用域相同,只是必须要有web环境支持,并配置相应容器监听器或拦截器从而能应用这些作用域。
Bean的定义、初始化、使用、销毁。
public class UserService {
public void init(){
//...
}
}
<bean id="userService" class="..." init-method="init"> </bean>
2.实现org.springframework.beans.factory.InitializingBean接口
public class UserService implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
//
}
}
<bean id="userService" class="...">bean>
BeanFactory factory=new ClassPathXmlApplicationContext("spring.xml");
UserService userService=(UserService)ac.getBean("userService");
方法二:使用ApplicationCotext
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService=(UserService)factory.getBean("userService");
public class UserService {
public void destory(){
//...
}
}
<bean id="userService" class="..." destory-method="destory"> </bean>
2.通过AbstractApplicationContext 对象,调用close方法销毁bean
AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
ctx.close();
IOC/DI 控制反转和依赖注入:
将对象实例化的创建过程交给外部容器(IOC容器,充当工厂角色)去负责;依赖注入即属性赋值操作。
代理模式目的旨在为服务类和客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。
为某一个对象(委托类)提供一个来的(代理类),用来控制对这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤、将请求分配给指定对象。
代理模式设计原则:
常见代理模式:
某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。
代理类和委托类有共同的父类或父接口。
代理类负责请求的处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
/**
* 定义接口-定义行为
*/
public interface Marry {
public void toMarry();
}
You.java(目标对象)
/**静态代理:
* 目标角色-实现行为
*/
public class You implements Marry{
@Override
public void toMarry() {
System.out.println("I will marry...");
}
}
MarryCompanyProxy.java(代理对象)
/**
* 静态代理:
* 代理角色:实现行为、增强用户行为
*/
public class MarryCompanyProxy implements Marry{
private Marry target;//目标对象
public MarryCompanyProxy(Marry target){
this.target=target;
}
@Override
public void toMarry() {
before();
target.toMarry();//调用目标对象的方法实现
after();
}
public void before(){
System.out.println("准备中...");
}
public void after(){
System.out.println("结束了...");
}
}
StaticProxy.java
public class StaticProxy {
public static void main(String[] args) {
You you=new You();
MarryCompanyProxy marryCompanyProxy=new MarryCompanyProxy(you);
marryCompanyProxy.toMarry();
Owner owner=new Owner();
AgentPorxy agentPorxy=new AgentPorxy(owner);
agentPorxy.toRentHouse();
}
}
public interface RentHouse {
public void toRentHouse();
}
RentHouse.java
public class Owner implements RentHouse{
@Override
public void toRentHouse() {
System.out.println("出租房屋!");
}
}
AgentPorxy.java
public class AgentPorxy implements RentHouse{
//目标对象
private RentHouse target;
//通过带参构造获取目标对象
public AgentPorxy(RentHouse target){
this.target=target;
}
@Override
public void toRentHouse() {
//before...
target.toRentHouse();
//after...
}
}
StaticProxy.java
public class StaticProxy {
public static void main(String[] args) {
Owner owner=new Owner();
AgentPorxy agentPorxy=new AgentPorxy(owner);
agentPorxy.toRentHouse();
}
}
相比较静态代理,动态代理在创建代理对象时更加灵活。
根据需要,会通过反射机制在程序运行期,动态为目标对象创建代理对象,无需程序员手动编写其源代码。
代理的行为可以代理多个方法,即满足生产需要的同时又达到代码通用的目的。
两种实现方式:
JDK动态代理就是在程序运行过程中,根据被代理的接口动态生成代理类的class文件,并加载运行的过程。
JDK提供了import java.lang.reflect.Proxy类来实现动态代理,可通过它的newProxyInstance方法来获得代理实现类。同时对于代理的接口的实际处理,是一个java.lang.reflect.InvocationHandler,它提供了invoke方法供实现者提供相应的代理逻辑的实现。
注意:JDK动态代理目标对象必须有接口实现。
每一个代理类都需要实现InvocationHandler
接口。
Proxy类:专门完成代理的操作类,可以通过此类为一个或多个接口动态生成实现类,次类提供了如下操作方法:
/**
* 返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序。(返回代理对象)
* @param loader (用来定义代理类的类加载器)一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
* @param interfaces (代理类实现的接口列表)表示将要给需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
* @param h (调度方法调用的调用处理函数)一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的invoke方法(传入InvocationHandler接口的子类)
* @return
* @throws IllegalArgumentException
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
/**
* method of Interface InvocationHandler
* @param proxy 调用该方法的代理实例
* @param method 目标对象的方法
* @param args 目标对象方法所需的参数
* @return
* @throws Throwable
*/
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
JdkHander.java
package com.xxxx.proxy;
import com.xxxx.proxy.staticProxy.Marry;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理
* 每一个代理类都需要实现InvocationHandler接口
*/
public class JdkHander implements InvocationHandler {
//目标对象
private Object target;//目标对象类型不固定,创建时动态生成。Marry、RentHouse
//通过带参构造器传递目标对象
public JdkHander(Object target){
this.target=target;
}
/**invoke
* 1.调用目标对象的方法(返回Object)
* 2.增强目标对象行为
* @param proxy 调用该方法的代理实例
* @param method 目标对象的方法
* @param args 目标对象方法所需的参数
* @return 从代理实例上的方法调用返回的值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强行为
//调用目标对象中的方法(返回Object)
Object object=method.invoke(target,args);
//增强行为
return object;
}
/**
* 获取代理对象:
* public static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
* Loader:类加载器
* interfaces:接口数组
* InvocationHandler:目标对象的接口数组
* @return
*/
public Object getProxy(){
/**
* 返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序。(返回代理对象)
* @param loader (用来定义代理类的类加载器)this.getClass().getClassLoader()
* @param interfaces (目标对象的接口数组)target.getClass().getInterfaces()
* @param h (InvocationHandler接口)传入InvocationHandler接口的实现类
* @return
* @throws IllegalArgumentException
*/
//Object object= Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
Object object=Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this );
return object;
}
}
JdkHandlerTest.java
package com.xxxx.proxy;
import com.xxxx.proxy.staticProxy.*;
public class JdkHandlerTest {
public static void main(String[] args) {
//目标对象
You you=new You();
//得到代理类
JdkHandler jdkHandler=new JdkHandler(you);
//得到代理对象
Marry marry=(Marry) jdkHandler.getProxy();
//通过代理对象调用目标对象的方法
marry.toMarry();
Owner owner=new Owner();
JdkHandler jdkHandler_o=new JdkHandler(owner);
RentHouse rentHouse=(RentHouse) jdkHandler_o.getProxy();
rentHouse.toRentHouse();
}
}
JDK动态代理只能代理实现了接口的类,而不能实现接口的类则不能使用JDK动态代理。
CGLIB是针对类来实现代理,其原理是对指定目标类生成一个子类,并覆盖其中方法实现增强,采用的是继承原理,所以不能对final修饰的类进行代理。
代理类继承目标类,重写目标类中方法。
1. 添加依赖
pom.xml文件引入cglib相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
2. 定义类,实现MethodInterceptor接口
通过带参构造得到目标对象target–>调用getProxy方法得到代理对象–>调用目标对象方法时会被拦截器所拦截,会调用intercept方法。
CglibInterceptor.java
package com.xxxx.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibInterceptor implements MethodInterceptor {
//目标对象
private Object target;
//通过带参构造器传递目标对象
public CglibInterceptor(Object target){
this.target=target;
}
//获取代理对象
public Object getProxy(){
//通过Enhancer类对象中的create()方法生成一个类,用于生成代理对象
Enhancer enhancer=new Enhancer();
//设置父类(将目标类作为代理类的父类)
enhancer.setSuperclass(target.getClass());
//设置拦截器,回调对象为本身对象
enhancer.setCallback(this);
//生成代理类对象并返回给调用着
return enhancer.create();
}
/**
* 拦截器:
* 1.目标对象的方法调用
* 2.行为增强
* @param o cglib动态生成的代理类实例
* @param method 实体类中所调用的被代理方法的引用
* @param objects 参数列表
* @param methodProxy 生成的代理类对方法的代理引用
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//增强行为
System.out.println("begin...");
//调用目标类中的方法
Object object=methodProxy.invoke(target,objects);
//增强行为
System.out.println("finish...");
return object;
}
}
package com.xxxx.proxy;
import com.xxxx.proxy.staticProxy.Marry;
import com.xxxx.proxy.staticProxy.You;
public class CglibInterceptorTest {
public static void main(String[] args) {
// //目标对象
// You you=new You();
// //得到拦截器
// CglibInterceptor cglibInterceptor=new CglibInterceptor(you);
// //得到代理对象
// Marry marry=(Marry) cglibInterceptor.getProxy();
// //通过代理对象调用目标对象的方法
// marry.toMarry();
User user=new User();
CglibInterceptor cglibInterceptor=new CglibInterceptor(user);
User user1=(User) cglibInterceptor.getProxy();
user1.test();
}
}
通过代理模式可以在指定位置执行对应流程,这样可以将一些横向的功能抽离出来形成一个独立的模块,然后在指定位置插入这些功能。这样的思想被称为面向切面编程,即AOP(Aspect Oriented Programing)。
aop考虑更多的是一种面到面的切入,即层与层之间的一种切入,所以称之为切面。
AOP能做什么:
主要应用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的复用。
AOP的特点:
AOP底层实现:
动态代理(JDK+CGLIB)
AOP基本概念:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.9version>
dependency>
<aop:aspectj-autoproxy/>
beans>
@Aspect
声明在类级别,声明类为切入面
@PoinCut
声明在方法级别,定义该方法为切入点
@Pointcut(“匹配规则”)
匹配规则execution(* com.xxxx.service.*.*(..))
第一个*代表方法的修饰范围(public、private、protected、*表示执行所有范围)
1.执行所有公共方法
execution(public *(..))
2.执行任意set方法
execution(* set*(..))
3.执行指定包下任意类的任意方法(如指定包;com.xxxx.service)
execution(* com.xxxx.service.*.*(..))
4.执行指定包及其子包下任意类的任意方法
execution(* com.xxxx.service..*.*(..))
package com.xxxx.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component//将对象交给IOC实例化
@Aspect//声明当前类是一个切面
public class LogCut {
//@Pointcut("execution(* *(..))")//定义为切入点
@Pointcut("execution(* com.xxxx.service..*.*(..))")
public void cut(){
}
/**
* 声明前置通知,并将通知应用到指定切入点上,目标类执行目标方法前会执行该通知
*/
@Before(value = "cut()")//该通知指向切入点cut()
public void before(){
System.out.println("前置通知...");
}
/**
* 声明返回通知,并将通知应用到指定切入点上,目标类执行目标方法无异常执行完会执行该通知
*/
@AfterReturning(value = "cut()")
public void afterReturn(){
System.out.println("返回通知...");
}
/**
* 声明最终通知,并将通知应用到指定切入点上,目标类执行目标方法执行完会执行该通知(有无异常最终都会执行)
*/
@After(value ="cut()")
public void after(){
System.out.println("最终通知...");
}
/**
* 声明异常通知,并将通知应用到指定切入点上,目标类方法执行目标方法执行异常会执行该通知
*/
@AfterThrowing(value = "cut()",throwing="e")
public void afterThrow(Exception e){
System.out.println("异常通知...");
}
/**
* 声明环绕通知,并将通知应用到指定切入点上
* 目标类方法执行前后都可通过该通知定义响应的处理
* 需要显示调用该方法,否则无法访问指定方法 pjp.proceed()
*/
@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕通知-前置通知...");
Object object=null;
try{
//显示调用对应的方法
object=pjp.proceed();
System.out.println(pjp.getTarget());
System.out.println("环绕通知-返回通知...");
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知-异常通知...");
}
System.out.println("环绕通知-最终通知...");
return object;
}
}
Test.java
package test;
import com.xxxx.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
}
}
环绕通知需要显式调用方法:ProceedingJoinPoint.proceed()
@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp){
Object object=null;
try{
//显示调用对应的方法
object=pjp.proceed();
System.out.println(pjp.getTarget());
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知-异常通知...");
}
System.out.println("环绕通知-最终通知...");
return object;
}
定义切面:
package com.xxxx.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component//将对象交给IOC实例化
//@Aspect//声明当前类是一个切面
public class LogCut02 {
public void cut(){
}
/**
* 声明前置通知,并将通知应用到指定切入点上,目标类执行目标方法前会执行该通知
*/
public void before(){
System.out.println("前置通知...");
}
/**
* 声明返回通知,并将通知应用到指定切入点上,目标类执行目标方法无异常执行完会执行该通知
*/
public void afterReturn(){
System.out.println("返回通知...");
}
/**
* 声明最终通知,并将通知应用到指定切入点上,目标类执行目标方法执行完会执行该通知(有无异常最终都会执行)
*/
public void after(){
System.out.println("最终通知...");
}
/**
* 声明异常通知,并将通知应用到指定切入点上,目标类方法执行目标方法执行异常会执行该通知
*/
public void afterThrow(){
System.out.println("异常通知...");
}
/**
* 声明环绕通知,并将通知应用到指定切入点上
* 目标类方法执行前后都可通过该通知定义响应的处理
* 需要显示调用该方法,否则无法访问指定方法 pjp.proceed()
*/
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕通知-前置通知...");
Object object=null;
try{
//显示调用对应的方法
object=pjp.proceed();
System.out.println(pjp.getTarget());
System.out.println("环绕通知-返回通知...");
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知-异常通知...");
}
System.out.println("环绕通知-最终通知...");
return object;
}
}
spring.xml
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.xxxx"/>
<aop:config>
<aop:aspect ref="logCut02">
<aop:pointcut id="cut" expression="execution(* com.xxxx.service..*.*(..))"/>
<aop:before method="before" pointcut-ref="cut"/>
<aop:after method="after" pointcut-ref="cut"/>
<aop:after-returning method="afterReturn" pointcut-ref="cut"/>
<aop:after-throwing method="afterThrow" pointcut-ref="cut"/>
<aop:around method="around" pointcut-ref="cut"/>
aop:aspect>
aop:config>
beans>
JAVA中开发定时任务主要有三种方案:
1.配置pom.xml
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.14version>
dependency>
package com.xxxx.task;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class TaskJob {
private SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public void job1(){
System.out.println("job1..."+df.format(new Date()));
}
public void job2(){
System.out.println("job2..."+df.format(new Date()));
}
}
<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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<!--设置自动化扫描范围-->
<context:component-scan base-package="com.xxxx"/>
<!--配置定时任务-->
<task:scheduled-tasks>
<!--ref表示任务类,method表示任务类定时方法,cron表示定时规则-->
<task:scheduled ref="taskJob" method="job1" cron="0/2 * * * * ?"/>
<task:scheduled ref="taskJob" method="job2" cron="0/4 * * * * ?"/>
</task:scheduled-tasks>
</beans>
corn表达式有至少6个(或7个)有空格分割的时间元素,这些元素依次为:
Cron表达式:
1.秒 0-59
2.分 0-56
3.小时 0-23
4.月份中日期 1-31
5.月份 1-12或JAN-SAT
6.星期中的日期 1-7或SUN-SAT
7.年份 1970-2099
*表示每一;
?表示不确定,可用在日和周几字段;
-表示指定一个范围; 10-15
,表示指定数个值; 5,10,15 第5,10,15*执行
/表示指定一个值的增加幅度; 0/5 0秒开始,每5秒执行一次
L表示last最后,比如一周的最后一天
W表示离当前日期最近的工作日,包括当天 15W 离15日最近的工作日
#表示该月第几个周几 6#3 该月第三个(3)周五(6)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<context:component-scan base-package="com.xxxx"/>
<task:annotation-driven/>
beans>
@Scheduled(cron="")
**package com.xxxx.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class TaskJob02 {
private SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Scheduled(cron = "0/2 * * * * ?")
public void job1(){
System.out.println("job1..."+df.format(new Date()));
}
@Scheduled(cron = "0/5 * * * * ?")
public void job2(){
System.out.println("job2..."+df.format(new Date()));
}
}
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.3.14version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.2.4.RELEASEversion>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.4.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>5.2.4.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.19version>
dependency>
<dependency>
<groupId>com.mchangegroupId>
<artifactId>c3p0artifactId>
<version>0.9.5.5version>
dependency>
#驱动名
#jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.driver=com.mysql.cj.jdbc.Driver
#数据库连接
#jdbc.url=jdbc:mysql://localhost:3306/datebaseName?
jdbc.url=jdbc:mysql://localhost:3306/spring_jdbc?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=UTC
#数据库用户名
jdbc.user=root
#数据库用户密码
jdbc.password=root
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.xxxx"/>
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
beans>
<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
bean>
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
获取模板类
JdbcTemplate jdbcTemplate= (JdbcTemplate) ac.getBean("jdbcTemplate");
crud操作
String sql="SELECT count(1) FROM tb_account";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class);
test01
package com.xxxx.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class SpringJdbcTest01 {
@Test
public void testJdbc(){
//获取上下文环境
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//获取模板类
JdbcTemplate jdbcTemplate= (JdbcTemplate) ac.getBean("jdbcTemplate");
//crud操作
String sql="SELECT count(1) FROM tb_account";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class);
System.out.println(total);
}
@Test
public void testJdbc02(){
//获取上下文环境
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//获取模板类
JdbcTemplate jdbcTemplate= (JdbcTemplate) ac.getBean("jdbcTemplate");
//crud操作
String sql="SELECT count(1) FROM tb_account WHERE user_id=?";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class,1);
System.out.println(total);
}
}
test02
package com.xxxx.test;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class SpringJdbcTest02 {
private JdbcTemplate jdbcTemplate;
@Before
public void init(){
//获取上下文环境
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//获取模板类
jdbcTemplate= (JdbcTemplate) ac.getBean("jdbcTemplate");
}
@Test
public void testJdbc(){
//crud操作
String sql="SELECT count(1) FROM tb_account";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class);
System.out.println(total);
}
@Test
public void testJdbc02(){
//crud操作
String sql="SELECT count(1) FROM tb_account WHERE user_id=?";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class,1);
System.out.println(total);
}
}
test03
package com.xxxx.test;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)//将测试运行在spring测试环境中
@ContextConfiguration(locations = {"classpath:spring.xml"})//设置要加载的配置文件
public class SpringJdbcTest03 {
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void testJdbc(){
//crud操作
String sql="SELECT count(1) FROM tb_account";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class);
System.out.println(total);
}
@Test
public void testJdbc02(){
//crud操作
String sql="SELECT count(1) FROM tb_account WHERE user_id=?";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class,1);
System.out.println(total);
}
}
test04 设计一个基础类,其他类继承该类
package com.xxxx.test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)//将测试运行在spring测试环境中
@ContextConfiguration(locations = {"classpath:spring.xml"})//设置要加载的配置文件
public class BaseTest {
}
package com.xxxx.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
public class SpringJdbcTest04 extends BaseTest{
@Resource
private JdbcTemplate jdbcTemplate;
@Test
public void testJdbc(){
//crud操作
String sql="SELECT count(1) FROM tb_account";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class);
System.out.println(total);
}
@Test
public void testJdbc02(){
//crud操作
String sql="SELECT count(1) FROM tb_account WHERE user_id=?";
Integer total=jdbcTemplate.queryForObject(sql,Integer.class,1);
System.out.println(total);
}
}
定义实体类:
Account.java
package com.xxxx.entity;
import java.util.Date;
/**
* 用户账户类:
*/
public class Account {
private Integer accountId;//账户id
private String accountName;//账户名称
private String accountType;//账户类型
private Double money;//账户金额
private String remark;//账户备注
private Integer userId;//用户id
private Date createTime;//创建时间
private Date updateTime;//修改事件
public Account() {
}
public Account(String accountName, String accountType, Double money, String remark, Integer userId) {
this.accountName = accountName;
this.accountType = accountType;
this.money = money;
this.remark = remark;
this.userId = userId;
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
定义接口类:
IAccountDao.java
package com.xxxx.dao;
import com.xxxx.entity.Account;
import java.util.List;
public interface IAccountDao {
/**
* 1.账户添加
* 添加账户记录,返回受影响的行数
* 批量添加账户记录,返回受影响的行数
* 添加账户记录,返回主键
*/
public int addAccount(Account account);
public int addAccountHasKey(Account account);
public int addAccountBatch(List<Account> accounts);
/**
* 2.账户修改
* 修改账户记录,返回受影响的行数
* 批量修改账户记录,返回受影响的行数
*/
public int updateAccount(Account account);
public int updateAccountBatch(List<Account> accounts);
/**
* 3.账户删除
* 删除账户记录,返回受影响的行数
* 批量删除账户记录,返回受影响的行数
*/
public int deleteAccount(int accountId);
public int deleteAccountBatch(Integer[] ids);
/**
* 4.账户查询
* 查询指定账户的账户总记录数,返回总记录数
* 查询指定账户的账户详情,返回账户对象
* 多条件查询指定用户的账户列表,返回账户集合
*/
public int queryAccountCount(int userId);
public Account queryAccountById(int accountId);
public List<Account> queryAccountByParams(Integer userId,String accountName,String accountType,String createTime);
}
账户模块实现类:
AccountDaoImpl.java
package com.xxxx.impl;
import com.xxxx.dao.IAccountDao;
import com.xxxx.entity.Account;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
/**
* 账户模块接口的实现类
*/
@Repository
public class AccountDaoImpl implements IAccountDao {
//注入JdbcTemplate模板类
@Resource
private JdbcTemplate jdbcTemplate;
@Override
public int addAccount(Account account) {}
@Override
public int addAccountHasKey(Account account) {}
@Override
public int addAccountBatch(List<Account> accounts) {}
@Override
public int updateAccount(Account account) {}
@Override
public int updateAccountBatch(List<Account> accounts) {}
@Override
public int deleteAccount(int accountId) {}
@Override
public int deleteAccountBatch(Integer[] ids) {}
@Override
public int queryAccountCount(int userId) {}
@Override
public Account queryAccountById(int accountId) {}
@Override
public List<Account> queryAccountByParams(Integer userId, String accountName, String accountType, String createTime) {}
添加单条记录返回受影响的行数
方法实现:
/**
* 添加单条记录,返回受影响行数
* @param account
* @return
*/
@Override
public int addAccount(Account account) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
//设置参数
Object[] objs={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId()};
int row=jdbcTemplate.update(sql,objs);
return row;
}
测试:
package com.xxxx.test;
import com.xxxx.dao.IAccountDao;
import com.xxxx.entity.Account;
import org.junit.Test;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
public class SpringJdbcAddTest extends BaseTest{
//注入IAccountDao
@Resource
private IAccountDao iAccountDao;
@Test
public void testAddCount(){
//准备要添加的数据
Account account=new Account("账户3","工商银行",200.0,"奖金",1);
//调用对象中的添加方法,返回行数
int row=iAccountDao.addAccount(account);
System.out.println("添加账户,受影响的行数:"+row);
}
}
添加单条记录返回主键:
方法实现:
/**
* 添加单条记录返回主键
* @param account
* @return
*/
@Override
public int addAccountHasKey(Account account) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
//设置参数
Object[] objs={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId()};
//定义KeyHolder 获取主键
KeyHolder keyHolder=new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps=connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.setString(1,account.getAccountName());
ps.setString(2,account.getAccountType());
ps.setDouble(3,account.getMoney());
ps.setString(4,account.getRemark());
ps.setInt(5,account.getUserId());
return ps;
}
}, keyHolder);
int key=keyHolder.getKey().intValue();
return key;
// jdbcTemplate.update(connection->{
// //预编译sql语句,并设置返回主键
// PreparedStatement ps= connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// //设置参数
// ps.setString(1,account.getAccountName());
// ps.setString(2,account.getAccountType());
// ps.setDouble(3,account.getMoney());
// ps.setString(4,account.getRemark());
// ps.setInt(5,account.getUserId());
// //返回预编译对象
// return ps;
// },keyHolder);
// //得到主键
// int key=keyHolder.getKey().intValue();
// return key;
}
测试:
@Test
public void testAddAccountHasKey(){
//准备要添加的数据
Account account=new Account("账户4","中国银行",800.0,"工资",2);
int key= iAccountDao.addAccountHasKey(account);
System.out.println("添加账户,返回主键:"+key);
}
批量添加多条记录:
方法实现:
/**
* 批量添加记录,返回受影响行数
* @param accounts
* @return
*/
@Override
public int addAccountBatch(List<Account> accounts) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
//循环遍历accounts
Account account=accounts.get(i);
//设置参数
ps.setString(1,account.getAccountName());
ps.setString(2,account.getAccountType());
ps.setDouble(3,account.getMoney());
ps.setString(4,account.getRemark());
ps.setInt(5,account.getUserId());
}
@Override
public int getBatchSize() {
return accounts.size();
}
}).length;
return rows;
}
测试:
@Test
public void testAddAccountBatch(){
//准备要添加的数据
Account account1=new Account("账户5","农业银行",200.0,"零花钱",3);
Account account2=new Account("账户6","工商银行",100.0,"餐饮费",3);
Account account3=new Account("账户7","中国银行",300.0,"交通费",3);
Account account4=new Account("账户8","中国银行",1000.0,"工资",3);
List<Account> accounts=new ArrayList<>();
accounts.add(account1);
accounts.add(account2);
accounts.add(account3);
accounts.add(account4);
int rows=iAccountDao.addAccountBatch(accounts);
System.out.println("批量添加账户,返回受影响行数:"+rows);
}
查询用户的账户总记录数:
方法实现:
/**
* 查询指定用户账户总记录数,返回记录数
* @param userId
* @return
*/
@Override
public int queryAccountCount(int userId) {
//sql语句
String sql="select count(*) from tb_account where user_id=?";
int count=jdbcTemplate.queryForObject(sql,Integer.class,userId);
return count;
}
测试:
@Test
public void testQueryAccountCount(){
//调用对象中的添加方法,返回行数
int total=iAccountDao.queryAccountCount(1);
System.out.println("查询user_id=1的总记录数:"+total);
}
查询指定账户,返回账户对象:
方法实现:
/**
* 查询指定账户的账户详情,返回账户对象
* @param accountId
* @return
*/
@Override
public Account queryAccountById(int accountId) {
String sql="select * from tb_account where user_id=?";
//查询对象
Account account=jdbcTemplate.queryForObject(sql,(ResultSet rs,int i) ->{
Account acc=new Account();
acc.setAccountId(accountId);
acc.setAccountName(rs.getString("account_name"));
acc.setAccountType(rs.getString("account_type"));
acc.setMoney(rs.getDouble("money"));
acc.setRemark(rs.getString("remark"));
acc.setUserId(rs.getInt("user_id"));
acc.setCreateTime(rs.getDate("create_time"));
acc.setUpdateTime(rs.getDate("update_time"));
return acc;
},accountId);
return account;
}
测试:
@Test
public void testQueryAccountById(){
//接收返回对象
Account account=iAccountDao.queryAccountById(1);
System.out.println("查询账户,返回对象:"+account);
}
多条件查询指定用户的账户列表,返回账户集合
方法实现:
/**
* 多条件查询指定用户的账户列表,返回账户集合
* @param userId 用户id
* @param accountName 账户名
* @param accountType 账户类型
* @param createTime 创建时间
* @return
*/
@Override
public List<Account> queryAccountByParams(Integer userId, String accountName, String accountType, String createTime) {
String sql="select * from tb_account where user_id=?";
//定义参数列表
List<Object> params=new ArrayList<>();
params.add(userId);
//判断参数是否为空,不为空则拼接sql语句以及设置对应参数
//account_name
if(StringUtils.isNotBlank(accountName)){
sql += " and account_name like concat('%',?,'%')";
//设置参数
params.add(accountName);
}
//account_type
if(StringUtils.isNotBlank(accountType)){
sql += " and account_type=?";
params.add(accountType);
}
//create_time
if(StringUtils.isNotBlank(createTime)){
sql += " and create_time < ?";
params.add(createTime);
}
//将集合转换成数组
Object[] objects=params.toArray();
List<Account> accountList=jdbcTemplate.query(sql, objects, new RowMapper<Account>() {
@Override
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account acc=new Account();
acc.setAccountId(resultSet.getInt("account_id"));
acc.setAccountName(resultSet.getString("account_name"));
acc.setAccountType(resultSet.getString("account_type"));
acc.setMoney(resultSet.getDouble("money"));
acc.setRemark(resultSet.getString("remark"));
acc.setUserId(resultSet.getInt("user_id"));
acc.setCreateTime(resultSet.getTimestamp("create_time"));
acc.setUpdateTime(resultSet.getDate("update_time"));
return acc;
}});
return accountList;
// Object[] objs={userId};
// List accountList=jdbcTemplate.query(sql,objs,(ResultSet rs,int i) -> {
// Account acc=new Account();
// acc.setAccountId(rs.getInt("account_id"));
// acc.setAccountName(rs.getString("account_name"));
// acc.setAccountType(rs.getString("account_type"));
// acc.setMoney(rs.getDouble("money"));
// acc.setRemark(rs.getString("remark"));
// acc.setCreateTime(rs.getDate("create_time"));
// acc.setUpdateTime(rs.getDate("updata_time"));
// return acc;
// });
// return accountList;
}
}
测试:
@Test
public void testQueryAccountByParams(){
// List accountList=iAccountDao.queryAccountByParams(3,null,null,null);
// List accountList=iAccountDao.queryAccountByParams(3,"5",null,null);
List<Account> accountList=iAccountDao.queryAccountByParams(3,"5","中国银行",null);
for (Account acc:accountList) {
System.out.println("账户id: "+acc.getAccountId());
}
}
更新指定账户记录,返回受影响行数
方法实现:
/**
* 修改账户记录,返回受影响的行数
* @param account
* @return
*/
@Override
public int updateAccount(Account account) {
//设置sql语句
String sql="update tb_account set account_name=?,account_type=?,money=?,remark=?,user_id=?,update_time=now() where account_id=?";
Object[] objects={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId(),account.getAccountId()};
int rows=jdbcTemplate.update(sql,objects);
return rows;
}
测试:
@Test
public void updateAccountTest(){
//设置需要更新的账户信息
Account account=new Account("账户8","农业银行",120.0,"零花钱",3);
account.setAccountId(14);
int rows=iAccountDao.updateAccount(account);
System.out.println(rows);
}
批量修改账户记录,返回受影响的行数
方法实现:
/**
* 批量修改账户记录,返回受影响的行数
* @param accounts
* @return
*/
@Override
public int updateAccountBatch(List<Account> accounts) {
String sql="update tb_account set account_name=?,account_type=?,money=?,remark=?,user_id=?,update_time=now() where account_id=?";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Account acc=accounts.get(i);
//设置参数
ps.setString(1,acc.getAccountName());
ps.setString(2,acc.getAccountType());
ps.setDouble(3,acc.getMoney());
ps.setString(4,acc.getRemark());
ps.setInt(5,acc.getUserId());
ps.setInt(6,acc.getAccountId());
}
@Override
public int getBatchSize() {
return accounts.size();
}
}).length;
return rows;
}
测试:
@Test
public void updateAccountBatchTest(){
//设置需要更新的账户信息
List<Account> accountList=new ArrayList<>();
Account account1=new Account("账户1","建设银行",180.0,"零花钱",1);
account1.setAccountId(14);
Account account2=new Account("账户2","交通银行",280.0,"零花钱",2);
account2.setAccountId(14);
Account account3=new Account("账户3","农业银行",300.0,"零花钱",3);
account3.setAccountId(14);
Account account4=new Account("账户4","中国银行",320.0,"零花钱",4);
account4.setAccountId(14);
accountList.add(account1);
accountList.add(account2);
accountList.add(account3);
accountList.add(account4);
int rows=iAccountDao.updateAccountBatch(accountList);
System.out.println(rows);
}
通过账户id删除单条记录,返回受影响行数
方法实现:
/**
* 删除账户记录,返回受影响的行数
* @param accountId
* @return
*/
@Override
public int deleteAccount(int accountId) {
String sql="delete from tb_account where account_id=?";
int rows=jdbcTemplate.update(sql,accountId);
return rows;
}
测试:
@Test
public void deleteAccountTest(){
int rows=iAccountDao.deleteAccount(18);
System.out.println(rows);
}
批量删除账户记录,返回受影响行数
方法实现:
/**
* 批量删除账户记录,返回受影响的行数
* @param ids
* @return
*/
@Override
public int deleteAccountBatch(Integer[] ids) {
String sql="delete from tb_account where account_id=?";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setInt(1,ids[i]);
}
@Override
public int getBatchSize() {
return ids.length;
}
}).length;
return rows;
}
测试:
@Test
public void deleteAccountBatchTest(){
Integer[] ids={11,12,13,14,15};
int rows=iAccountDao.deleteAccountBatch(ids);
System.out.println(rows);
}
用户账户类 — Account.java
package com.xxxx.entity;
import java.util.Date;
/**
* 用户账户类:
*/
public class Account {
private Integer accountId;//账户id
private String accountName;//账户名称
private String accountType;//账户类型
private Double money;//账户金额
private String remark;//账户备注
private int userId;//用户id
private Date createTime;//创建时间
private Date updateTime;//修改事件
public Account() {
}
public Account(String accountName, String accountType, Double money, String remark, Integer userId) {
this.accountName = accountName;
this.accountType = accountType;
this.money = money;
this.remark = remark;
this.userId = userId;
}
public Integer getAccountId() {
return accountId;
}
public void setAccountId(Integer accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getAccountType() {
return accountType;
}
public void setAccountType(String accountType) {
this.accountType = accountType;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
}
账户模块接口定义 — IAccountDao.java(interface)
package com.xxxx.dao;
import com.xxxx.entity.Account;
import java.util.List;
/**
* 账户模块 定义接口
* 1.账户添加
* 添加账户记录,返回受影响的行数
* 批量添加账户记录,返回受影响的行数
* 添加账户记录,返回主键
* 2.账户修改
* 修改账户记录,返回受影响的行数
* 批量修改账户记录,返回受影响的行数
* 3.账户删除
* 删除账户记录,返回受影响的行数
* 批量删除账户记录,返回受影响的行数
* 4.账户查询
* 查询指定账户的账户总记录数,返回总记录数
* 查询指定账户的账户详情,返回账户对象
* 多条件查询指定用户的账户列表,返回账户集合
*/
public interface IAccountDao {
/**
* 1.账户添加
* 添加账户记录,返回受影响的行数
* 批量添加账户记录,返回受影响的行数
* 添加账户记录,返回主键
*/
public int addAccount(Account account);
public int addAccountHasKey(Account account);
public int addAccountBatch(List<Account> accounts);
/**
* 2.账户修改
* 修改账户记录,返回受影响的行数
* 批量修改账户记录,返回受影响的行数
*/
public int updateAccount(Account account);
public int updateAccountBatch(List<Account> accounts);
/**
* 3.账户删除
* 删除账户记录,返回受影响的行数
* 批量删除账户记录,返回受影响的行数
*/
public int deleteAccount(int accountId);
public int deleteAccountBatch(Integer[] ids);
/**
* 4.账户查询
* 查询指定账户的账户总记录数,返回总记录数
* 查询指定账户的账户详情,返回账户对象
* 多条件查询指定用户的账户列表,返回账户集合
*/
public int queryAccountCount(int userId);
public Account queryAccountById(int accountId);
public List<Account> queryAccountByParams(Integer userId,String accountName,String accountType,String createTime);
/**
* 支出
* @param accountId
* @param money
* @return
*/
public int outAccount(Integer accountId,double money);
/**
* 收入
* @param accountId
* @param money
* @return
*/
public int inAccount(Integer accountId,double money);
}
账户模块接口实现类 — AccountDaoImpl.java
package com.xxxx.impl;
import com.xxxx.dao.IAccountDao;
import com.xxxx.entity.Account;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* 账户模块接口的实现类
*/
@Repository
public class AccountDaoImpl implements IAccountDao {
//注入JdbcTemplate模板类
@Resource
private JdbcTemplate jdbcTemplate;
/**
* 添加单条记录,返回受影响行数
* @param account
* @return
*/
@Override
public int addAccount(Account account) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
//设置参数
Object[] objs={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId()};
int row=jdbcTemplate.update(sql,objs);
return row;
}
/**
* 添加单条记录返回主键
* @param account
* @return
*/
@Override
public int addAccountHasKey(Account account) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
//设置参数
Object[] objs={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId()};
//定义KeyHolder 获取主键
KeyHolder keyHolder=new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps=connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
ps.setString(1,account.getAccountName());
ps.setString(2,account.getAccountType());
ps.setDouble(3,account.getMoney());
ps.setString(4,account.getRemark());
ps.setInt(5,account.getUserId());
return ps;
}
}, keyHolder);
int key=keyHolder.getKey().intValue();
return key;
// jdbcTemplate.update(connection->{
// //预编译sql语句,并设置返回主键
// PreparedStatement ps= connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// //设置参数
// ps.setString(1,account.getAccountName());
// ps.setString(2,account.getAccountType());
// ps.setDouble(3,account.getMoney());
// ps.setString(4,account.getRemark());
// ps.setInt(5,account.getUserId());
// //返回预编译对象
// return ps;
// },keyHolder);
// //得到主键
// int key=keyHolder.getKey().intValue();
// return key;
}
/**
* 批量添加记录,返回受影响行数
* @param accounts
* @return
*/
@Override
public int addAccountBatch(List<Account> accounts) {
//定义sql语句
String sql="insert into tb_account(account_name,account_type,money,remark,user_id,create_time,update_time)" +
"values(?,?,?,?,?,now(),now())";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
//循环遍历accounts
Account account=accounts.get(i);
//设置参数
ps.setString(1,account.getAccountName());
ps.setString(2,account.getAccountType());
ps.setDouble(3,account.getMoney());
ps.setString(4,account.getRemark());
ps.setInt(5,account.getUserId());
}
@Override
public int getBatchSize() {
return accounts.size();
}
}).length;
return rows;
}
/**
* 修改账户记录,返回受影响的行数
* @param account
* @return
*/
@Override
public int updateAccount(Account account) {
//设置sql语句
String sql="update tb_account set account_name=?,account_type=?,money=?,remark=?,user_id=?,update_time=now() where account_id=?";
Object[] objects={account.getAccountName(),account.getAccountType(),account.getMoney(),account.getRemark(),account.getUserId(),account.getAccountId()};
int rows=jdbcTemplate.update(sql,objects);
return rows;
}
/**
* 批量修改账户记录,返回受影响的行数
* @param accounts
* @return
*/
@Override
public int updateAccountBatch(List<Account> accounts) {
String sql="update tb_account set account_name=?,account_type=?,money=?,remark=?,user_id=?,update_time=now() where account_id=?";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Account acc=accounts.get(i);
//设置参数
ps.setString(1,acc.getAccountName());
ps.setString(2,acc.getAccountType());
ps.setDouble(3,acc.getMoney());
ps.setString(4,acc.getRemark());
ps.setInt(5,acc.getUserId());
ps.setInt(6,acc.getAccountId());
}
@Override
public int getBatchSize() {
return accounts.size();
}
}).length;
return rows;
}
/**
* 删除账户记录,返回受影响的行数
* @param accountId
* @return
*/
@Override
public int deleteAccount(int accountId) {
String sql="delete from tb_account where account_id=?";
int rows=jdbcTemplate.update(sql,accountId);
return rows;
}
/**
* 批量删除账户记录,返回受影响的行数
* @param ids
* @return
*/
@Override
public int deleteAccountBatch(Integer[] ids) {
String sql="delete from tb_account where account_id=?";
int rows=jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setInt(1,ids[i]);
}
@Override
public int getBatchSize() {
return ids.length;
}
}).length;
return rows;
}
/**
* 查询指定用户账户总记录数,返回记录数
* @param userId
* @return
*/
@Override
public int queryAccountCount(int userId) {
//sql语句
String sql="select count(*) from tb_account where user_id=?";
int count=jdbcTemplate.queryForObject(sql,Integer.class,userId);
return count;
}
/**
* 查询指定账户的账户详情,返回账户对象
* @param accountId
* @return
*/
@Override
public Account queryAccountById(int accountId) {
String sql="select * from tb_account where user_id=?";
//查询对象
Account account=jdbcTemplate.queryForObject(sql,(ResultSet rs,int i) ->{
Account acc=new Account();
acc.setAccountId(accountId);
acc.setAccountName(rs.getString("account_name"));
acc.setAccountType(rs.getString("account_type"));
acc.setMoney(rs.getDouble("money"));
acc.setRemark(rs.getString("remark"));
acc.setUserId(rs.getInt("user_id"));
acc.setCreateTime(rs.getDate("create_time"));
acc.setUpdateTime(rs.getDate("update_time"));
return acc;
},accountId);
return account;
}
/**
* 多条件查询指定用户的账户列表,返回账户集合
* @param userId 用户id
* @param accountName 账户名
* @param accountType 账户类型
* @param createTime 创建时间
* @return
*/
@Override
public List<Account> queryAccountByParams(Integer userId, String accountName, String accountType, String createTime) {
String sql="select * from tb_account where user_id=?";
//定义参数列表
List<Object> params=new ArrayList<>();
params.add(userId);
//判断参数是否为空,不为空则拼接sql语句以及设置对应参数
//account_name
if(StringUtils.isNotBlank(accountName)){
sql += " and account_name like concat('%',?,'%')";
//设置参数
params.add(accountName);
}
//account_type
if(StringUtils.isNotBlank(accountType)){
sql += " and account_type=?";
params.add(accountType);
}
//create_time
if(StringUtils.isNotBlank(createTime)){
sql += " and create_time < ?";
params.add(createTime);
}
//将集合转换成数组
Object[] objects=params.toArray();
List<Account> accountList=jdbcTemplate.query(sql, objects, new RowMapper<Account>() {
@Override
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account acc=new Account();
acc.setAccountId(resultSet.getInt("account_id"));
acc.setAccountName(resultSet.getString("account_name"));
acc.setAccountType(resultSet.getString("account_type"));
acc.setMoney(resultSet.getDouble("money"));
acc.setRemark(resultSet.getString("remark"));
acc.setUserId(resultSet.getInt("user_id"));
acc.setCreateTime(resultSet.getTimestamp("create_time"));
acc.setUpdateTime(resultSet.getDate("update_time"));
return acc;
}});
return accountList;
// Object[] objs={userId};
// List accountList=jdbcTemplate.query(sql,objs,(ResultSet rs,int i) -> {
// Account acc=new Account();
// acc.setAccountId(rs.getInt("account_id"));
// acc.setAccountName(rs.getString("account_name"));
// acc.setAccountType(rs.getString("account_type"));
// acc.setMoney(rs.getDouble("money"));
// acc.setRemark(rs.getString("remark"));
// acc.setCreateTime(rs.getDate("create_time"));
// acc.setUpdateTime(rs.getDate("updata_time"));
// return acc;
// });
// return accountList;
}
/**
* 支出
* @param accountId
* @param money
* @return
*/
@Override
public int outAccount(Integer accountId, double money) {
String sql="update tb_account set money = money - ? where account_id=?";
Object[] objects={money,accountId};
int rows=jdbcTemplate.update(sql,objects);
return rows;
}
/**
* 收入
* @param accountId
* @param money
* @return
*/
@Override
public int inAccount(Integer accountId, double money) {
String sql="update tb_account set money=money+? where account_id=?";
Object[] objects={money,accountId};
int rows=jdbcTemplate.update(sql,objects);
return rows;
}
}
结果测试:
package com.xxxx.test;
import com.xxxx.service.AccountService;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.annotation.Resource;
public class SpringJdbcTest05 extends BaseTest{
@Resource
private AccountService accountService;
@Test
public void test(){
//account_id=1向account_id转账200
int rs=accountService.updateAccountByTranfer(1,2,200.0);
if(rs==1){
System.out.println("转账成功! "+rs);
}else {
System.out.println("转账失败!"+rs);
}
}
}
事务四大特性:
Spring事务核心接口:
Spring并不直接管理事务,而是提供多种事务管理器,将事务委托给Hibernate
或者JTA
等持久化机制所提供的相关平台框架的事务来实现。
Spring事务管理器接口org.springframework.transaction.PlatformTransactionManager
,通过这个接口为各个平台如JDBC、Hibernate等提供了对应的事务管理器。接口内容如下:
public interface PlatformTransactionManager extends TransactionManager {
//由TransactionDefinition 得到TransactionStatus 对象
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交
void commit(TransactionStatus var1) throws TransactionException;
//回滚
void rollback(TransactionStatus var1) throws TransactionException;
}
Spring并不关心具体的事务管理机制,只是为不同的事务API提供一致的编程模型。
如果应用程序中直接使用JDBC来进行持久化,此时使用DataSourceTransactionManager
来处理事务边界,首先需要将下面的xml内容装配到应用程序的上下文定义中:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
实际上,DataRourseTransactionManager是通过调用java.sql.Connection来管理事务,后者是通过DataSource获取到的。通过连接commit()方法来提交事务,同样,事务失败则通调用rollback()方法,进行回滚。
如果应用程序持久化通过Hibernate实现,那么需要使用HibernateTransactionManager
。对于Hibernate3需要在spring上下文中添加如下声明:
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory">
bean>
sessionFactory属性需要装配一个Hibernate的session工厂,HibernateTransactionManager实现细节是它将事务管理职责委托给org.hibernate.Transaction对象,而后者是从Hibernate Session中获取到的。当事务成功完成时,HibernateTransactionManager将会调用Transaction对象的commit()方法,反之将会调用rollback()方法。
使用JPA需要使用Spring的JpaTransactionManager
来处理事务。需要在spring中配置JpaTranscationManager:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
bean>
JpaTranscationManager只需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTranscationManager将与由工厂所产生的JpaEntitynManager合作来构建事务。
如果应用程序没有使用以上所述事务管理,或是跨越了多个事务管理源(比如两个或者多个不同的数据源),此时需要使用JtaTransactionManager
:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:/TranscationManager"/>
bean>
JtaTransactionManager将事务管理任务责任委托给javax.transactio.UserTranscation和javax.transaction.TransactionManager对象,其中事务成功完成通过UserTransaction.commit()方法提交,事务失败通过UserTransaction.rollback()方法回滚。
通过jdbc持久化事务,对于事务配置实现有两种方法:xml配置、注解配置
1. 添加命名空间
在spring.xml配置文件添加事务和aop的命名空间
事务:
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
AOP:
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<aop:aspectj-autoproxy/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="query*" read-only="true"/>
<tx:method name="delete*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="cut" expression="execution(* com.xxxx.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
aop:config>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="txManager"/>
@Transactional(propagation = Propagation.REQUIRED)