Spring框架学习 学习视频链接
spring version:5.2.6
Spring的简要概述
Spring 是轻量级的开源的 JavaEE 框架
Spring 有两个核心部分:IOC 和 AOP
(1)IOC:控制反转,把创建对象过程交给 Spring 进行管理
(2)AOP:面向切面,不修改源代码进行功能增强
Spring的下载地址:https://repo.spring.io/release/org/springframework/spring/
Spring的运行需要第三方的日志包依赖(common-logging.jar,下载地址:http://commons.apache.org/proper/commons-logging/download_logging.cgi ),maven依赖
1 2 3 4 5 <dependency > <groupId > commons-logging</groupId > <artifactId > commons-logging</artifactId > <version > 1.2</version > </dependency >
Spring模块
SpringIOC所需的基本包为日志包以及Spring模块图中的Core Container中的jar包
Spring的重要组成部分 ** IOC 概念与原理
什么是 IOC
(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
(2)使用 IOC 目的:为了耦合度降低
(3)做入门案例就是 IOC 实现
IOC 底层原理:xml 解析、工厂模式、反射
BeanFactory接口
IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂
Spring 提供 IOC 容器实现两种方式:(两个接口)
(1)BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用
加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
(2)ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
ApplicationContext 接口的两个常用实现类
1 2 3 4 5 6 ApplicationContext context1 = new ClassPathXmlApplicationContext("beans/beans01.xml" ); ApplicationContext context2 = new FileSystemXmlApplicationContext("E:\\spring\\spring5\\src\\beans\\beans01.xml" )
Bean管理
概念:Bean管理指的是两个操作,Spring创建对象与Spring注入属性。
操作方式:(1)基于 xml 配置文件方式实现。(2)基于注解方式实现。
基于xml方式的Bean管理 User类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.hyn.spring5;public class User { private String username; private String password; public void add () { System.out.println("add......." ); } public User (String username, String password) { this .username = username; this .password = password; } public User () { } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } }
xml
1 <bean id ="user" class ="com.hyn.spring5.User" />
bean管理默认使用无参构造方法创建对象
id 属性:唯一标识
class属性:类全路径(包类路径)
DI:依赖注入(即注入属性)
p名称空间注入(了解)
1 2 3 <bean id ="user" class ="com.hyn.spring5.User" p:username ="admin" p:password ="admin" > </bean >
字面量
null值
1 <property name ="password" > <null > </null > </property >
xml方式的特殊字符处理
1 2 3 4 5 6 <property name ="username" > <value > <![CDATA[<<>>]]]> </value > </property >
属性ref
1 2 3 4 5 6 7 <bean id ="userService" class ="com.hyn.spring5.service.UserService" > <property name ="userDao" ref ="userDaoImpl" > </property > </bean > <bean id ="userDaoImpl" class ="com.hyn.spring5.dao.UserDaoImpl" > </bean >
xml自动装配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 </bean > -->> <bean id ="dept" class ="com.atguigu.spring5.autowire.Dept" > </bean > <bean id ="emp" class ="com.atguigu.spring5.autowire.Emp" autowire ="byType" > </bean > <bean id ="dept" class ="com.atguigu.spring5.autowire.Dept" > </bean >
xml注入集合属性 1、注入数组类型属性 2、注入 List 集合类型属性 3、注入 Map 集合类型属性
创建类,定义数组、list、map、set 类型属性,生成对应 set 方法
Stu类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class Stu { private String[] courses; private List<String> list; private Map<String, String> maps; private Set<String> sets; private List<Course> courseList; @Override public String toString () { return "Stu{" + "courses=" + Arrays.toString(courses) + ", list=" + list + ", maps=" + maps + ", sets=" + sets + ", courseList=" + courseList + '}' ; } public void setCourses (String[] courses) { this .courses = courses; } public void setList (List<String> list) { this .list = list; } public void setMaps (Map<String, String> maps) { this .maps = maps; } public void setSets (Set<String> sets) { this .sets = sets; } public void setCourseList (List<Course> courseList) { this .courseList = courseList; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <bean id ="course1" class ="com.hyn.spring5.collectiontype.Course" > </bean > <bean id ="course2" class ="com.hyn.spring5.collectiontype.Course" > </bean > <bean id ="stu" class ="com.hyn.spring5.collectiontype.Stu" > <property name ="courses" > <array > <value > java课程</value > <value > 数据库课程</value > </array > </property > <property name ="list" > <list > <value > 张三</value > <value > 李四</value > </list > </property > <property name ="maps" > <map > <entry key ="JAVA" value ="java" > </entry > <entry key ="CPP " value ="cpp" > </entry > </map > </property > <property name ="sets" > <set > <value > idea</value > <value > eclipse</value > </set > </property > <property name ="courseList" > <list > <ref bean ="course1" > </ref > <ref bean ="course2" > </ref > </list > </property > </bean >
测试代码
1 2 3 4 5 public void testCollectiontype () { ApplicationContext context = new ClassPathXmlApplicationContext("beans/beans02.xml" ); Stu stu = context.getBean("stu" , Stu.class ) ; System.out.println(stu); }
使用util标签将集合注入部分提取出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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:util ="http://www.springframework.org/schema/util" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <util:list id ="bookList" > <value > 易筋经</value > <value > 九阴真经</value > <value > 九阳神功</value > </util:list > <bean id ="stu" class ="com.hyn.spring5.collectiontype.Stu" > <property name ="list" ref ="bookList" > </property > </bean > </beans >
工厂bean(FactoryBean)
Spring有两种类型的bean,一种普通bean,另一种为工厂bean(FactoryBean)
普通bean:在配置文件中定义的bean类型就是返回类型
工厂bean:在配置文件中定义的bean类型可以喝返回类型不一样
创建类,让这个类作为工厂bean,实现接口FactoryBean
实现接口里面的方法,在实现的方法中定义返回的bean类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class MyBean implements FactoryBean <Course > { @Override public Course getObject () throws Exception { Course course = new Course(); course.setCname("abc" ); return course; } @Override public Class<?> getObjectType() { return null ; } @Override public boolean isSingleton () { return false ; } }
1 <bean id ="myBean" class ="com.atguigu.spring5.factorybean.MyBean" > </bean >
1 2 3 4 5 6 @Test public void test3 () { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml" ); Course course = context.getBean("myBean" , Course.class ) ; System.out.println(course); }
bean的作用域 在Spring中,默认情况下bean是单实例对象
通过scope属性设置bean为单实例还是多实例
(1)在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
(2)scope 属性值
第一个值 默认值,singleton ,表示是单实例对象
第二个值 prototype ,表示是多实例对象
(3)singleton 和 prototype 区别
第一 singleton 单实例,prototype 多实例
第二 设置 scope 值是 singleton 时,加载 spring 配置文件时候就会创建单实例对象
设置 scope 值是 prototype 时,不是在加载 spring 配置文件时候创建 对象,在调用getBean 方法时候创建多实例对象
bean的生命周期
生命周期 :从对象创建到对象销毁的过程
bean 生命周期
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
3、演示 bean 生命周期 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { System.out.println("在初始化之前执行的方法" ); return bean; } @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { System.out.println("在初始化之后执行的方法" ); return bean; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Orders { public Orders () { System.out.println("第一步 执行无参数构造创建 bean 实例" ); } private String oname; public void setOname (String oname) { this .oname = oname; System.out.println("第二步 调用 set 方法设置属性值" ); } public void initMethod () { System.out.println("第三步 执行初始化的方法" ); } public void destroyMethod () { System.out.println("第五步 执行销毁的方法" ); } }
xml
1 2 3 4 <bean id ="orders" class ="com.atguigu.spring5.bean.Orders" init method ="initMethod" destroy-method ="destroyMethod" > <property name ="oname" value ="手机" > </property > </bean > <bean id ="myBeanPost" class ="com.atguigu.spring5.bean.MyBeanPost" > </bean >
外部配置文件(properties文件) 配置数据库信息
引入druid包
创建外部属性文件(properties格式文件)
1 2 3 4 5 prop.dirverClass =com.mysql.jdbc.Driver prop.url =jdbc:mysql://localhost:3306/hyn prop.username =root prop.password =root
jdbc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" > <context:property-placeholder location ="classpath:jdbc.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${prop.dirverClass}" > </property > <property name ="url" value ="${prop.url}" > </property > <property name ="username" value ="${prop.username}" > </property > <property name ="password" value ="${prop.password}" > </property > </bean > </beans >
注解引入
什么是注解 (1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..) (2)使用注解,注解作用在类上面,方法上面,属性上面 (3)使用注解目的:简化 xml 配置
Spring 针对 Bean 管理中创建对象提供注解 (1)@Component (2)@Service (表service层) (3)@Controller (表web层) (4)@Repository (表dao层)
上面四个注解功能是一样的,都可以用来创建 bean 实例。
引入依赖,并开启组件扫描
依赖包:spring-aop
开启组件扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <context:component-scan base-package ="com.atguigu" > </context:component-scan > <context:component-scan base-package ="com.atguigu" use-default filters ="false" > <context:include-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /></context:component-scan > <context:component-scan base-package ="com.atguigu" > <context:exclude-filter type ="annotation" expression ="org.springframework.stereotype.Controller" /></context:component-scan >
使用注解
1 2 3 4 5 6 7 8 9 @Component (value = "userService" ) public class UserService { public void add () { System.out.println("service add......." ); } }
基于注解的属性注入(均不需要set方法)
(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据名称进行注入
(3)@Resource:可以根据类型注入,可以根据名称注入(不属于spring,是javax下的注解 )
(4)@Value:注入普通类型属性
(5)使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Autowired private User user; *
完全注解开发
1 2 3 4 5 @Configuration @ComponentScan (basePackages = "com.hyn.spring5" )public class SpringConfig {}
1 2 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class ) ;
** AOP 概念 面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
通俗描述:不通过修改源代码的方式,在主干功能里面添加新功能
底层原理(jdk动态代理与cglib动态代理) AOP的底层采用动态代理,有两种情况。
有接口,使用jdk动态代理
无接口使用cglib动态代理
jdk动态代理(有接口) 使用Proxy(java.lang.reflect.Proxy)
类里面的方法创建对象。
方法:
1 2 3 4 5 6 7 8 public static Object newProxyInstance (ClassLoader loader, // 类加载器 Class<?>[] interfaces, // 代理类实现的接口列表 InvocationHandler h)
返回的类是一个实现所有interfaces的代理类($Proxy
,这个类会由该方法动态编写)。假设实现类是Demo
,那么我们得到的代理类强转为Demo类型(Demo与代理类同层次 ),只能向上转型。且&Proxy
是在内存中的,我们看不到它。
若想查看&Proxy
的源码,则需要在测试类的mian
方法中测试(不能使用@Test
单元测试),在newProxyInstance
方法前,加上一行代码。
1 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" );
然后idea的工程目录下就会多出一个com文件夹,找到其中的.class文件,打开即可(文件需要反编译,idea会自动帮我们完成,但用记事本打开会是乱码 )。
匿名内部类实现jdk代理
JDKProxy类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.hyn.spring.aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class JDKProxy { public static UserDao createProxyUseDao (UserDaoImpl userDao) { UserDao proxyUserDao = (UserDao) Proxy.newProxyInstance( JDKProxy.class .getClassLoader (), userDao .getClass ().getInterfaces (), new InvocationHandler () { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法执行前:" ); Object result = method.invoke(userDao, args); System.out.println("方法执行后:" ); return result; } }); return proxyUserDao; } }
Test
1 2 3 4 5 6 public static void main (String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles" , "true" ); UserDao userDao = JDKProxy.createProxyUseDao(new UserDaoImpl()) userDao.add(); userDao.update(); }
$Proxy0类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 package com.sun.proxy;import com.hyn.spring.aop.UserDao;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy0 extends Proxy implements UserDao { private static Method m1; private static Method m2; private static Method m3; private static Method m0; private static Method m4; public $Proxy0(InvocationHandler var1) throws { super (var1); } public final boolean equals (Object var1) throws { try { return (Boolean)super .h.invoke(this , m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String toString () throws { try { return (String)super .h.invoke(this , m2, (Object[])null ); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void add () throws { try { super .h.invoke(this , m3, (Object[])null ); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode () throws { try { return (Integer)super .h.invoke(this , m0, (Object[])null ); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final void update () throws { try { super .h.invoke(this , m4, (Object[])null ); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object" ).getMethod("equals" , Class.forName("java.lang.Object" )); m2 = Class.forName("java.lang.Object" ).getMethod("toString" ); m3 = Class.forName("com.hyn.spring.aop.UserDao" ).getMethod("add" ); m0 = Class.forName("java.lang.Object" ).getMethod("hashCode" ); m4 = Class.forName("com.hyn.spring.aop.UserDao" ).getMethod("update" ); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
cglib动态代理 假设需要增强的类是UserService
,cglib需要将其作为父类,然后创建它的子类作为代理类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package com.hyn.spring.aop;import org.springframework.cglib.core.DebuggingClassWriter;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class UserService { public void add () { System.out.println("UserService: add...." ); } public void update () { System.out.println("UserService: update...." ); } } class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("执行方法前。" ); methodProxy.invokeSuper(o, objects); System.out.println("执行方法后。" ); return null ; } } class CglibProxy { public static UserService createUserService (UserService userService) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\\cglib\\code" ); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class ) ; enhancer.setCallback(new MyMethodInterceptor()); return (UserService) enhancer.create(); } }
testCglib
1 2 3 4 5 6 @Test public void testCglib () { UserService userService = CglibProxy.createUserService(new UserService()); userService.add(); userService.update(); }
AOP术语
连接点:类里面可以被增强的方法
切入点:真正增强的方法
通知(增强)
实际增强的逻辑部分称为通知(增强)
通知有多种类型
切面:是动作,将通知应用到切入点的过程
AOP操作
Spring框架一般都是基于AspectJ实现AOP操作,但AspectJ不是Spring的组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用。
所需jar包:
基于AspectJ实现AOP操作
(1) 基于xml配置文件实现
(2) 基于注解方式实现
切入点表达式
1 2 3 4 5 6 7 8 (1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强 (2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) ) 举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强 execution(* com.atguigu.dao.BookDao.add(..)) 举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强 execution(* com.atguigu.dao.BookDao.* (..)) 举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强 execution(* com.atguigu.dao.*.* (..))
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package com.hyn.spring.aopanno;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.springframework.stereotype.Component;@Component @Aspect public class UserProxy { @Pointcut (value = "execution(* com.hyn.spring.aopanno.User.add(..))" ) public void myPoint () {} @Before (value = "execution(* com.hyn.spring.aopanno.User.add(..))" ) public void before () { System.out.println("前置通知" ); } @AfterReturning (value = "myPoint()" ) public void afterReturning () { System.out.println("后置通知" ); } @After (value = "myPoint()" ) public void after () { System.out.println("最终通知" ); } @Around (value = "myPoint()" ) public void around (ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕前" ); proceedingJoinPoint.proceed(); System.out.println("环绕后" ); } @AfterThrowing (value = "myPoint()" ) public void afterThrowing () { System.out.println("异常通知" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.hyn.spring.aopanno;import org.springframework.stereotype.Component;@Component (value = "user" )public class User { public void add () { System.out.println("User: add..." ); } public void update () { System.out.println("User: update..." ); } }
xml文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation =" http://www.springframework.org/schema/beans http://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.hyn.spring.aopanno" /> <aop:aspectj-autoproxy proxy-target-class ="false" > </aop:aspectj-autoproxy > </beans >
替换该配置文件的配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 package com.hyn.spring.aopanno;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;import org.springframework.stereotype.Component;@Configuration @ComponentScan (basePackages = "com.hyn.spring.aopanno" ) @EnableAspectJAutoProxy (proxyTargetClass = false ) public class ConfigAOP {}
Test
1 2 3 4 5 6 7 @Test public void aopTest () { AbstractApplicationContext context = new ClassPathXmlApplicationContext("aop.xml" ); User user = context.getBean("user" , User.class ) ; user.add(); user.update(); }
AOP的纯xml文件写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <bean id ="user" class ="com.hyn.spring.aopanno.User" > </bean > <bean id ="userProxy" class ="com.hyn.spring.aopanno.UserProxy" > </bean > <aop:config > <aop:pointcut id ="myPoint" expression ="execution(* com.hyn.spring.aopanno.User.add(..))" /> <aop:aspect ref ="userProxy" > <aop:before method ="before" pointcut-ref ="myPoint" /> <aop:after-returning method ="afterReturning" pointcut-ref ="myPoint" /> <aop:after method ="after" pointcut-ref ="myPoint" /> <aop:around method ="around" pointcut-ref ="myPoint" /> <aop:after-throwing method ="afterThrowing" pointcut-ref ="myPoint" /> </aop:aspect > </aop:config > </beans >
有多个增强类多同个方法进行增强,设置增强类优先级 在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
1 2 3 4 5 @Component @Aspect @Order (1 )public class PersonProxy {}
JdbcTemplate(不常用) jar包
新增包:jdbc,oxm,tx,druid,mysql-connector-java
jdbcTemplate的常用方法 方法所属类:org.springframework.jdbc.core.JdbcTemplate
1、public int update(String sql, @Nullable Object... args)
参数:
sql:执行的sql语句,未知值用?代替
args:?的具体值
返回值:执行完sql语句,表受影响的行数
2、public <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args)
参数:
sql:执行的sql语句,未知值用?代替
rowMapper:查询结果需返回的类型(不可为基本数据类型)。(若返回Integer。写法:new BeanPropertyRowMapper(Integer.class))
args:?的具体值
返回值:查询结果
3、public <T> List<T> query(String sql, RowMapper<T> rowMapper)
sql:执行的sql语句,未知值用?代替
rowMapper:查询结果需返回的类型(不可为基本数据类型)。(若返回Integer。写法:new BeanPropertyRowMapper(Integer.class))
args:?的具体值
返回值:查询结果,并以list的形式返回
4、public int[] batchUpdate(String sql, List<Object[]> batchArgs)
批量操作,一个sql语句执行多次。(内部实现也就是for循环)
参数:
sql:执行的sql语句,未知值用?代替
batchArgs:第一方法中args的list
返回值:每执行完一条sql语句,表受影响的行数。以数组形式返回
示例 jdbc.properties(注意驱动包与数据库版本的冲突问题)
1 2 3 4 prop.dirverClass =com.mysql.jdbc.Driver prop.url =jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf-8&userSSL=false&serverTimezone=GMT%2B8 prop.username =root prop.password =root
jdbcBeans.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?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" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd " > <context:component-scan base-package ="com.hyn.spring.jdbctemplate" > </context:component-scan > <context:property-placeholder location ="classpath:jdbc.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${prop.dirverClass}" > </property > <property name ="url" value ="${prop.url}" > </property > <property name ="username" value ="${prop.username}" > </property > <property name ="password" value ="${prop.password}" > </property > </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > </beans >
新建数据库与表
新建User,并完成get,set,toString, 有参构造,无参构造等方法的编写。(略)
新建UserDao,UserService两个接口,编写相应方法。并编写其实现类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.hyn.spring.jdbctemplate.dao;import com.hyn.spring.jdbctemplate.bean.User;import java.util.List;public interface UserDao { public int add (User user) ; public int delete (User user) ; public int update (User user) ; public List<User> findAllUsers () ; public User findUserById (int id) ; public int selectUserCount () ; public int [] batchAddUser(List<Object[]> batchArgs); public int [] batchDeleteUser(List<Object[]> batchArgs); public int [] batchUpdateUser(List<Object[]> batchArgs); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package com.hyn.spring.jdbctemplate.dao;import com.hyn.spring.jdbctemplate.bean.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.stereotype.Repository;import java.util.List;@Repository public class UserDaoImpl implements UserDao { @Autowired private JdbcTemplate jdbcTemplate; @Override public int add (User user) { String sql = "INSERT INTO t_user (`id`, `username`, `status`) VALUES (?, ?, ?)" ; return jdbcTemplate.update(sql, user.getId(), user.getUsername(), user.getStatus()); } @Override public int delete (User user) { String sql = "DELETE FROM t_user WHERE `id` = ?" ; return jdbcTemplate.update(sql, user.getId()); } @Override public int update (User user) { String sql = "UPDATE t_user SET `username` = ?, `status` = ? WHERE `id` = ?" ; return jdbcTemplate.update(sql, user.getUsername(), user.getStatus(), user.getId()); } @Override public List<User> findAllUsers () { String sql = "SELECT * FROM t_user" ; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class )) ; } @Override public User findUserById (int id) { String sql = "SELECT * FROM t_user WHERE id = ?" ; return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class ), id ) ; } @Override public int selectUserCount () { String sql = "SELECT COUNT(*) FROM t_user" ; return jdbcTemplate.queryForObject(sql, Integer.class ).intValue () ; } @Override public int [] batchAddUser(List<Object[]> batchArgs) { String sql = "INSERT INTO t_user (`id`, `username`, `status`) VALUES (?, ?, ?)" ; return jdbcTemplate.batchUpdate(sql, batchArgs); } @Override public int [] batchDeleteUser(List<Object[]> batchArgs) { String sql = "DELETE FROM t_user WHERE `id` = ?" ; return jdbcTemplate.batchUpdate(sql, batchArgs); } @Override public int [] batchUpdateUser(List<Object[]> batchArgs) { String sql = "UPDATE t_user SET `username` = ?, `status` = ? WHERE `id` = ?" ; return jdbcTemplate.batchUpdate(sql, batchArgs); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package com.hyn.spring.jdbctemplate.service;import com.hyn.spring.jdbctemplate.bean.User;import java.util.List;public interface UserService { public void add (User user) ; public void delete (User user) ; public void update (User user) ; public void findAllUsers () ; public void findUserById (int id) ; public void selectUserCount () ; public void batchAddUser (List<Object[]> batchArgs) ; public void batchDeleteUser (List<Object[]> batchArgs) ; public void batchUpdateUser (List<Object[]> batchArgs) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.hyn.spring.jdbctemplate.service;import com.hyn.spring.jdbctemplate.bean.User;import com.hyn.spring.jdbctemplate.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.Arrays;import java.util.List;@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public void add (User user) { System.out.println(userDao.add(user)); } @Override public void delete (User user) { System.out.println(userDao.delete(user)); } @Override public void update (User user) { System.out.println(userDao.update(user)); } @Override public void findAllUsers () { System.out.println(userDao.findAllUsers()); } @Override public void findUserById (int id) { System.out.println(userDao.findUserById(id)); } @Override public void selectUserCount () { System.out.println(userDao.selectUserCount()); } @Override public void batchAddUser (List<Object[]> batchArgs) { System.out.println(Arrays.toString(userDao.batchAddUser(batchArgs))); } @Override public void batchDeleteUser (List<Object[]> batchArgs) { System.out.println(Arrays.toString(userDao.batchDeleteUser(batchArgs))); } @Override public void batchUpdateUser (List<Object[]> batchArgs) { System.out.println(Arrays.toString(userDao.batchUpdateUser(batchArgs))); } }
Test类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package com.hyn.spring.jdbctemplate.Test;import com.hyn.spring.jdbctemplate.bean.User;import com.hyn.spring.jdbctemplate.service.UserService;import com.hyn.spring.jdbctemplate.service.UserServiceImpl;import org.junit.Test;import org.springframework.context.support.AbstractApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.ArrayList;import java.util.List;public class jdbcTest { @Test public void test () { AbstractApplicationContext context = new ClassPathXmlApplicationContext("jdbcBeans.xml" ); UserService userService = context.getBean("userServiceImpl" , UserServiceImpl.class ) ; List<Object[]> batchArgs = new ArrayList<>(); Object[] o1 = { "java" , "1" , "1" }; Object[] o2 = { "cpp" , "2" , "2" }; batchArgs.add(o1); batchArgs.add(o2); userService.batchUpdateUser(batchArgs); } }
事务 1、事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层) 2、在 Spring 进行事务管理操作 (1)有两种方式:编程式事务管理和声明式事务管理(使用)
3、声明式事务管理 (1)基于注解方式(使用) (2)基于 xml 配置文件方式 4、在 Spring 进行声明式事务管理,底层使用 AOP 原理 5、Spring 事务管理 API
提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
Spring与MyBatis框架使用DataSourceTransactionManager
。
示例说明 例子:用户之间的转账
数据库 1 2 3 4 5 6 7 8 9 10 11 USE user_db;DROP TABLE IF EXISTS t_user;CREATE TABLE t_user( `id` INT PRIMARY KEY auto_increment, `username` VARCHAR (50 ) NOT NULL , `money` INT ); INSERT INTO t_user(`username` , `money` ) VALUES ('A' , '2500' );INSERT INTO t_user(`username` , `money` ) VALUES ('B' , '1500' );INSERT INTO t_user(`username` , `money` ) VALUES ('C' , '2000' );INSERT INTO t_user(`username` , `money` ) VALUES ('D' , '3000' );
根据表编写相应的User类(略)
xml配置
另需tx约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <?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: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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd " > <context:component-scan base-package ="com.hyn.spring" > </context:component-scan > <context:property-placeholder location ="jdbc.properties" /> <bean id ="dataSource" class ="com.alibaba.druid.pool.DruidDataSource" > <property name ="driverClassName" value ="${prop.dirverClass}" > </property > <property name ="url" value ="${prop.url}" > </property > <property name ="username" value ="${prop.username}" > </property > <property name ="password" value ="${prop.password}" > </property > </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="transactionManager" class ="org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <tx:annotation-driven transaction-manager ="transactionManager" /> </beans >
properties文件略
dao层 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.hyn.spring.dao;import com.hyn.spring.bean.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.jdbc.core.BeanPropertyRowMapper;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.stereotype.Repository;import org.springframework.transaction.PlatformTransactionManager;@Repository (value = "userDao" )public class UserDao { @Autowired @Qualifier (value = "jdbcTemplate" ) private JdbcTemplate jdbcTemplate; public User findUserById (int id) { String sql = "SELECT * FROM t_user WHERE `id` = ?" ; return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class ), id ) ; } public int reduceMoney (User user) { String sql = "UPDATE t_user SET `money` = ? - 100 WHERE `id` = ?" ; return jdbcTemplate.update(sql, user.getMoney(), user.getId()); } public int addMoney (User user) { String sql = "UPDATE t_user SET `money` = ? + 100 WHERE `id` = ?" ; return jdbcTemplate.update(sql, user.getMoney(), user.getId()); } }
Service层 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.hyn.spring.service;import com.hyn.spring.bean.User;import com.hyn.spring.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Service (value = "userService" )@Transactional public class UserService { @Autowired @Qualifier (value = "userDao" ) private UserDao userDao; public User findUserById (int id) { return userDao.findUserById(id); } public void accountMoney (User A, User B) { userDao.reduceMoney(A); int i = 10 / 0 ; userDao.addMoney(B); } }
@Transactional 的参数 鼠标放其后面,Ctrl+P参看 )
红框内的为常用参数。
propagation:事务传播行为。多事务方法直接进行调用,这个过程中事务 是如何进行管理的
Spring所定义的7种传播行为:
isolation:事务隔离级别,用来解决脏读、不可重复读、虚(幻)读的问题
默认值:Isolation.DEFAULT
,使用所连接的数据库的默认隔离规则。
timeout:超时时间,单位s。-1为无穷大
readOnly:是否只读
rollbackFor:出现哪些异常回滚
noRollbackFor:出现哪些异常不回滚
推荐博客:https://www.cnblogs.com/clwydjgs/p/9317849.html(rollbackFor的详解)
(借上面链接表格一用)
属性
类型
描述
value
String
可选的限定描述符,指定使用的事务管理器
propagation
enum: Propagation
可选的事务传播行为设置
isolation
enum: Isolation
可选的事务隔离级别设置
readOnly
boolean
读写或只读事务,默认读写
timeout
int (in seconds granularity)
事务超时时间设置
rollbackFor
Class对象数组,必须继承自Throwable
导致事务回滚的异常类数组
rollbackForClassName
类名数组,必须继承自Throwable
导致事务回滚的异常类名字数组
noRollbackFor
Class对象数组,必须继承自Throwable
不会导致事务回滚的异常类数组
noRollbackForClassName
类名数组,必须继承自Throwable
不会导致事务回滚的异常类名字数组
使用
1 @Transactional (propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = -1 , readOnly = false , rollbackFor = Exception.class )
Test 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.hyn.spring.test;import com.hyn.spring.bean.User;import com.hyn.spring.service.UserService;import org.junit.Test;import org.springframework.context.support.AbstractApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserTest { @Test public void test01 () { AbstractApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); UserService userService = context.getBean("userService" , UserService.class ) ; User A = userService.findUserById(1 ); User B = userService.findUserById(2 ); System.out.println(A); System.out.println(B); userService.accountMoney(A, B); System.out.println("转账成功" ); } }