1.Spring
1.1简介
是一个轻量级控制反转(ioc)和面向切面(AOP)的容器框架
-
目的:解决企业开发复杂性
-
理念:使现有技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
-
SSM: SpringMVC+Spring+Mybatis
1.2优点
-
Spring是一个开源的免费的框架
-
Spring是一个轻量级的,非入侵式的框架
-
控制反转(IOC),面向切面编程(AOP)
-
支持事务的处理,对框架整合的支持
Spring就是一个轻量级的控制反转和面向切面编程的框架
1.3组成
1.4 拓展
现代化的Java开发就是基于Spring的开发
-
SpringBoot
-
一个快速开发的脚手架
-
基于SpringBoot可以快速开发单个微服务
-
约定大于配置
-
-
SpringCloud
-
基于SpringBoot实现
-
弊端:发展了太久违背了最初的理念!配置十分繁琐(“配置地狱”)
2. IOC
-
UserDao接口
-
UserDaolmpl实现类
-
UserService业务接口
-
UserServicelmpl业务实现类
IOC是一个容器
2.1 IOC底层原理
控制反转--依靠DI依赖注入
-
降低耦合度
原理:
xml解析+工厂模式+反射
2.2 IOC接口(BeanFactory)
-
IOC的思想基于IOC容器,底层就是对象工厂
-
Spring提供两种实现方式
-
BeanFatory:IOC最基本的实现,开发中一般不使用
加载配置文件时不会创建对象,在获取或使用对象时才会创建对象
-
ApplicationContext:BeanFatory的子接口,开发人员使用
加载配置文件时,就会创建配置文件中的对象(例如服务器启动时就将对象创建完毕)
-
-
ApplicationContext实现类
2.3 IOC操作Bean管理(基于xml配置文件set方法)
Bean管理:
-
由Spring创建对象
-
由Spring注入属性
基于xml配置文件创建对象并注入属性
-
xmlns
-
用于指定命名空间,当命名空间不同时,同样的词条代表不同的含义
-
例如:html中的list与java中的list出现在同一份xml文档中,此时就需要指定命名空间
-
-
xsi:schemalocation
-
指定了XML namespace和对应的XSD(Xml schema definition)的位置关系
-
创建对象:
<?xml version="1.0" encoding="UTF-8"?> <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="hello" class="com.wang.pojo.Hello"> <property name="str" value="Spring"/> </bean> </beans>
使用bean标签并添加属性
-
常用属性
-
id属性(对象的别名),唯一的标识
-
class属性(对象的类的全路径)
-
创建对象时,默认执行无参构造方法(没有无参方法就会报错)
注入属性:
DI(依赖注入),就是输入属性(前提是在创建对象的过程中DI)
-
set方法注入
-
有参构造注入
package com.wang.pojo; //不使用Spring方法 public class Book { private String bname; public void setBname(String bname) { this.bname = bname; } public Book(String bname) { this.bname = bname; } public static void main(String[] args) { //原始方式set方法注入 //Book book = new Book(); // book.setBname("abc"); //有参构造注入 Book book = new Book("abc"); } }
Spring DI方法:
在Spring配置文件配置对象创建,配置属性注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置对象创建 --> <bean id="book" class="com.wang.pojo.Book"> <property name="bname" value="易经"/> <property name="author" value="我"/> </bean> </beans>
package com.wang.pojo; public class Book { //不能添加有参构造方法 private String bname; private String author; public void setBname(String bname) { this.bname = bname; } public void setAuthor(String author) { this.author = author; } public void Prin(){ System.out.println(this.author); System.out.println(this.bname); } }
2.4 IOC操作Bean管理(基于xml注解方式有参构造)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置对象创建 --> <!--有参构造输入 --> <bean id="book" class="com.wang.pojo.Book"> <constructor-arg name="bname" value="易经"></constructor-arg> <constructor-arg name="author" value="你"></constructor-arg> </bean> </beans>
//Java main函数代码不变
2.5 注入其他属性
字面量:
-
null值
-
属性值包含特殊符号
<!-- 向属性里设置空值--> <property name="author" value="我"></property> <property name="bname" > <null> </null> </property>
<!-- 向属性值中添加特殊符号 1.将尖括号进行转义,< 2.带有特殊符号的写到CDATA --> <property name="bname" value="<<难京>>"></property> <property name="author" > <value><![CDATA[<<南京>>]]></value> </property>
注入属性-外部Bean,内部Bean,级联赋值
-
外部Bean
package com.wang; import com.wang.dao.UserDao; import com.wang.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestBean { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = context.getBean("userService",UserService.class); userService.add(); } }
<?xml version="1.0" encoding="UTF-8"?> <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.wang.service.UserService"> <property name="userDao" ref="userDaoImp"></property> </bean> <bean id="userDaoImp" class="com.wang.dao.UserDaoImp"></bean> </beans>
-
内部Bean
当存在一对多的关系时,使用内部Bean
例如员工和部门
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="emp" class="com.wang.test.Emp"> <property name="ename" value="wdd"></property> <property name="gender" value="男"></property> <property name="dept" > <bean id="dept" class="com.wang.test.Dept"> <property name="dname" value="开发部"></property> </bean> </property> </bean> </beans>
-
级联赋值
<?xml version="1.0" encoding="UTF-8"?> <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="emp" class="com.wang.test.Emp"> <property name="ename" value="wdd"></property> <property name="gender" value="男"></property> <property name="dept" ref ="dept"></property> </bean> <bean id="dept" class="com.wang.test.Dept" <property name="dname" value="开发部"></property> </beans> </beans>
2.6 注入集合属性
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 集合类型属性注入--> <bean id="stu" class="spring5.Stu"> <!-- 数组类型属性--> <property name="courses"> <array> <value>java课程</value> <value>数据库课程</value> </array> </property> <!-- list类型属性--> <property name="list"> <list> <value>zhangsan</value> <value>xiaosan</value> </list> </property> <!-- map类型属性--> <property name="maps"> <map> <entry key="JAVA" value="java"></entry> <entry key="PHP" value="php"></entry> </map> </property> <!-- set类型属性--> <property name="sets"> <set> <value>MySQL</value> <value>Redis</value> </set> </property> </bean> </beans>
<!-- 注入list类型属性,值是对象--> <property name="courseList"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property>
2.7 FactoryBean
Bean和FactoryBean
-
Bean:
-
在配置文件定义的bean类型就是返回类型
-
-
FatoryBean:
-
在配置文件中定义的bean类型可以和返回类型不同
-
FatoryBean的实现:
-
创建类,让这个类实现接口FactoryBean
-
实现接口中的方法,在实现的方法中定义返回的bean类型
package com.wang.test; import org.springframework.beans.factory.FactoryBean; public class MyBean implements FactoryBean { @Override public Dept getObject() throws Exception { Dept dept = new Dept(); dept.setDname("开发部"); return dept; } @Override public Class<?> getObjectType() { return null; } }
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd" > <bean id="mybean" class="com.wang.test.MyBean"> </bean> </beans>
package com.wang; import com.wang.dao.UserDao; import com.wang.pojo.Book; import com.wang.service.UserService; import com.wang.test.Dept; import com.wang.test.Emp; import com.wang.test.MyBean; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class TestBean { public static void main(String[] args) throws Exception { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Dept myBean = context.getBean("mybean", Dept.class); System.out.println(myBean.getDname()); } }
2.8 Bean管理
Bean的作用域
可以设置bean对象是单实例对象还是多实例对象
对象地址相同就表明是单例
bean标签的scope用于设置
-
singleton(默认值)单实例
-
prototype多实例
-
设置为prototype时,不是加载spring配置文件时创建对象,是在调用getBean方法时创建的多实例对象
-
多实例对象:
<?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 https://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="book" scope="prototype" class="com.wang.pojo.Book"> <property name="bname" ref="booklist"></property> </bean> </beans>
单实例对象:
<?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 https://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="book" scope="singleton" class="com.wang.pojo.Book"> <property name="bname" ref="booklist"></property> </bean> </beans>
区别:
Bean的生命周期
-
无参构造创建Bean
-
为Bean的属性设置值和对其他Bean的使用
-
调用bean初始化的方法
-
bean对象可以使用
-
容器关闭--启动bean销毁方法
我们知道对于普通的 Java 对象来说,它们的生命周期就是:
-
实例化
-
该对象不再被使用时通过垃圾回收机制进行回收
而对于 Spring Bean 的生命周期来说:
-
实例化 Instantiation
-
属性赋值 Populate
-
初始化 Initialization
-
销毁 Destruction
通过构造器创建bean实例(无参数构造) 为bean的属性设置值和对其他bean引用(调用set方法) 把bean实例传递给bean后置处理器的方法,postProcessBeforeInitialization 调用bean的初始化的方法(需要进行配置) 把bean实例传递给bean后置处理器的方法,postProcessAfterInitialization bean可以使用了(对象获取到了) 当容器关闭时,调用bean的销毁方法(需要进行配置)
postProcess方法会实现BeanPostProcessor
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; } }
2.9 XML自动装配
根据指定装配规则,Spring自动将匹配的属性值进行注入
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="emp" class="com.wang.test.Emp" autowire="byName"> </bean> <bean id="deptFcous" class="com.wang.test.Dept"></bean> </beans>
package com.wang.test; public class Emp { private String ename; public String gender; private Dept deptFcous; public void setDept(Dept dept) { this.deptFcous = deptFcous; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } public void say(){ System.out.println("我是"+this.deptFous.getDname()+"的"); } }
2.10 IOC操作Bean管理
外部属性文件
-
直接配置数据库信息
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--直接配置连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://localhost:3306/school"></property> <property name="username" value="root"></property> <property name="password" value="zhixingheyi0"></property> </bean> </beans>
-
properties文件读入Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context"> <!--引用外部配置文件--> <context:property-placeholder location="com.wang:jdbc.properties"></context:property-placeholder> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${a.driverclass}"></property> <property name="url" value="${a.url}"></property> <property name="username" value="${a.username}"></property> <property name="password" value="${a.password}"></property> </bean> </beans>
a.driverClass=com.mysql.jdbc.Driver a.url=jdbc:mysql://localhost:3306/school a.userName=root a.password=zhixingheyi0
基于注解方式
使用注解的目的:简化xml配置
Spring针对Bean创建对象的注解:(四类注解功能无区别,不同名称的目的是便于开发)
-
@Componet
-
@Service
-
@Controller
-
@Repository
基于注解的类对象注入:
-
开启组件扫描(告诉Spring容器在哪些类上加上了注解,去扫描这些类所在的包和类)
-
在类上加上注解,默认创建该类的对象
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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.wang.test"></context:component-scan> </beans>
package com.wang.test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class Emp { private String ename; public String gender; //此处必须注解 //根据属性类型自动装配 @Autowired private Dept dept; public void setDept(Dept dept) { this.dept = dept; } public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } public void say(){ System.out.println("我是"+this.dept.getDname()+"的"); } }
package com.wang.test; import org.springframework.stereotype.Component; @Component public class Dept { private String dname; public void setDname(String dname) { this.dname = dname; } public String getDname() { return dname; } }
package com.wang.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test1 { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Emp emp = context.getBean("emp",Emp.class); emp.say(); } }
基于注解的属性注入:
-
@AutoWired 根据属性类型进行自动装配
-
@Qualifier 根据属性名称注入(与@AutoWired配合使用)
@Autowired //根据类型进行注入 @Qualifier(value = "dept") private Dept dept;
-
@Resource 根据类型或名城注入
-
@Value 注入普通数据类型属性
完全注解开发(实际开发使用Springboot开发)
-
创建配置类,替代xml的配置文件
package com.wang; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration //作为配置类,作为xml配置文件 @ComponentScan(basePackages = {"com.wang"})//等价于扫描com.wang包 public class SpringConfig { }
-
使用配置类开发
package com.wang.test; import com.wang.SpringConfig; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test1 { @Test public void test(){ ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); Emp emp = context.getBean("emp",Emp.class); emp.say(); } }
3. AOP
-
面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
-
通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
3.1 AOP概念以及原理
3.2 AOP-JDK动态代理
动态代理,通俗点说就是:无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。
-
使用Proxy类里面的方法实现(newProxyInstance)
-
ClassLoader类加载器
-
增强方法所在的类,这个类实现的接口,可以有多个接口
-
实现这个接口InvocationHandler,创建代理对象,写增强的方法
-
动态代理 基本用法:
-
定义接口类
package com.wang.Demo001; public interface UserDao { public int add(int a,int b); public String update(String id); }
-
实现接口类
package com.wang.Demo001; public class UserDaoIMPL implements UserDao{ @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
-
使用动态代理
-
调用Proxy.newProxyInstance方法得到接口类的代理对象(传入被代理的对象W)
-
实现接口的InvocationHandler,在其中添加增强逻辑
-
package com.wang.Demo001; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; public class JDKProxy { public static void main(String[] args) { //创建接口实现类的对象 UserDaoIMPL userDaoIMPL = new UserDaoIMPL(); Class[] interfaces = {UserDao.class}; UserDao userDao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDaoProxy(userDaoIMPL)); System.out.println(userDao.add(1,2)); } static class UserDaoProxy implements InvocationHandler{ //传递需要代理的对象 private Object object; //有参构造传递 public UserDaoProxy(Object obj){ this.object = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行:"+method.getName()+"传递的参数"+ Arrays.toString(args)); //被增强的方法 Object res = method.invoke(object,args); //方法之后 System.out.println("方法之后执行"+object); return res; } } }
3.3 术语
-
连接点:类里面可以被增强的方法
-
切入点:实际被增强的方法
-
通知(增强):实际增强的逻辑部分
-
前置通知(增强的方法之前执行)
-
后置通知
-
环绕通知
-
异常通知(方法出现异常会执行)
-
最终通知(finally)
-
-
切面:把通知应用到切入点的过程
3.4 AOP操作
-
Spring框架一般就是AspectJ实现AOP操作
-
AspectJ不是Spring组成部分,是独立AOP框架,一般把AspectJ和Spring框架一起使用
-
-
基于AspectJ实现AOP操作
-
基于xml配置文件实现
-
基于注解实现
-
-
切入点表达式
-
作用:搞清楚对哪个类的那个方法进行增强
-
语法结构 :
-
execution([权限修饰符] [返回类型] [类的全路径] [方法名称]([参数列表])
-
举例:
-
对com.wang.dao.BookDao类里面的add进行增强
-
execution(*com.wang.dao.BookDao.add(..))
-
对所有方法进行增强
-
execution(*com.wang.dao.BookDao.*(..))
3.5AOP操作(AspectJ注解)
-
创建类,在类中定义方法
package com.wang.AOPAnnotation; public class User { public void add(){ System.out.println("add...."); } }
-
创建增强类(编写增强的逻辑)
-
在增强类里面创建方法,让不同的方法代表不同通知类型
-
package com.wang.AOPAnnotation; public class UserProxy { //前置通知 public void before(){ System.out.println("befor......."); } }
-
进行通知的配置
-
在Spring配置文件中,开启注解扫描
-
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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.wang.AOPAnnotation"></context:component-scan> </beans>
-
-
使用注解创建User和UserProxy
-
package com.wang.AOPAnnotation; import org.springframework.stereotype.Component; @Component public class UserProxy { //前置通知 public void before(){ System.out.println("befor......."); } }
-
-
在增强类上添加注解@Aspect
-
package com.wang.AOPAnnotation; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; //增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //前置通知 public void before(){ System.out.println("befor......."); } }
-
-
在Spring配置文件中开启生成代理对象
-
<!--开启AspectJ生成注解对象,扫描有@Aspect注解的类,有这个注解的就生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
-
-
配置不同类型的通知
-
在增强类里面,通知方法上面添加通知类型的注解,使用切入点表达式配置
-
不同类型的通知
-
package com.wang.AOPAnnotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //切入点 @Pointcut(value = "execution(* com.wang.AOPAnnotation.User.add())") public void pointdemo(){ } //前置通知,在增强方法的前置执行 @Before(value = "execution(* com.wang.AOPAnnotation.User.add())") public void before(){ System.out.println("before......."); } //后置通知 @After(value = "execution(* com.wang.AOPAnnotation.User.add())") public void after(){ System.out.println("after........"); } //在方法两头执行 @Around(value = "pointdemo()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前...."); proceedingJoinPoint.proceed(); System.out.println("环绕之后...."); } //在返回结果之后执行 @AfterReturning(value = "pointdemo()") public void afterReturning(){ System.out.println("afterreturning"); } }
注解 | 作用 | 备注 |
---|---|---|
@Before | 被增强方法之前 | |
@After | 被增强方法之后 | |
@AfterThrowing | 异常通知 | |
@AfterReturning | 返回结果之后执行 | |
@Around | 环绕通知 | 传入ProceedingJoinPoint参数,早于Before,晚于After |
@Pointcut | 抽取公共切入点 | 相当于将多次使用的方法做一个通用空方法代替他 |
-
相同切入点抽取
// 相同切入点抽取 @Pointcut(value = "execution(* spring5.aopanno.User.add(..))") public void pointdemo() { }
-
有多个增强类对同一个方法进行增强,设置增强类优先级
-
在增强类上添加注解@Prder,数字越小优先级越高
-
@Component @Aspect//生成代理对象 @Order(1)//优先级为1
-
完全注解开发,创建配置类,不需要配置xml文件
@Configuration @ComponentScan(basePackages = {"com.wang"}) @EnableAspectJAutoProxy(proxyTargetClass = true) // 替代配置文件中的 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> public class ConfigAop { }
public void test(){ // 加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class); UserService userService = context.getBean("userService",UserService.class); System.out.println(userService); userService.add(); }
3.6 AOP操作(AspectJ配置文件)
4. JdbcTemplate
Spring框架对JDBC进行封装,使用JdbcTemplate方便实现对数据库操作
4.1 概述和准备
<?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 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.wang"></context:component-scan> <!--引入外部属性文件--> <context:property-placeholder location="classpath:JDBC.properties"></context:property-placeholder> <!--配置数据库连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${prop.url}"></property> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="username" value="${prop.username}"></property> <property name="password" value="${prop.password}"></property> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql:///school prop.username=root prop.password=zhixingheyi0
创建Service类,创建Dao类
-
在dao注入jdbcTemplate对象
-
在service注入dao对象
package com.wang.JdbcTemplate.dao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookDaoImpl implements BookDao{ //注入jdbcTemplate,用它实现数据库的增删改查 @Autowired private JdbcTemplate jdbcTemplate; }
package com.wang.JdbcTemplate.service; import com.wang.JdbcTemplate.dao.BookDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BookService { //注入dao @Autowired private BookDao bookDao; }
4.2 JdbcTemplate对数据库操作
创建实体类,对应数据库中的表
package com.wang.JdbcTemplate.entity; public class User { private String user_id; private String username; private String userstatus; public String getUser_id() { return user_id; } public void setUser_id(String user_id) { this.user_id = user_id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserstatus() { return userstatus; } public void setUserstatus(String userstatus) { this.userstatus = userstatus; } }
4.3 添加操作
-
编写service和dao
-
在dao进行数据库添加操作
-
调用JdbcTemplate对象的update方法实现添加操作
-
package com.wang.JdbcTemplate.dao; import com.wang.JdbcTemplate.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookDaoImpl implements BookDao{ //注入jdbcTemplate,用它实现数据库的增删改查 @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(User user) { String sql = "insert into t_user value(?,?,?)"; Object[] args = {user.getUser_id(),user.getUsername(),user.getUserstatus()}; System.out.println(jdbcTemplate.update(sql,args)); } }
方法参数:
-
sql语句
-
可变参数,设置sql语句的值
package com.wang.JdbcTemplate.dao; import com.wang.JdbcTemplate.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BookDaoImpl implements BookDao{ //注入jdbcTemplate,用它实现数据库的增删改查 @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(User user) { String sql = "insert into t_user value(1,?,?)"; Object[] args = {user.getUser_id(),user.getUsername(),user.getUserstatus()}; System.out.println(jdbcTemplate.update(sql,args)); } }
4.4 修改和删除
@Override public void updateBook(Book book) { //1 创建sql语句 String sql="update t_book set userName=?,userStatus=? where userId=?"; //2 调用方法实现 Object[] args={book.getUserName(),book.getUserStatus(),book.getUserId()}; int update=jdbcTemplate.update(sql,args);//返回影响的行数 System.out.println(update); }
@Override public void delete(String id) { //1 创建sql语句 String sql="delete from t_book where userId=?"; //2 调用方法实现 int update=jdbcTemplate.update(sql,id);//返回影响的行数 System.out.println(update); }
4.5 查询
jdbcTemplate.queryForObject(sql,xxx.class); //第一个参数:sql语句 //第二个参数:返回类型Class @Override public int selectCount() { String sql="select count(*) from t_book"; return jdbcTemplate.queryForObject(sql,Integer.class); }
4.6 查询对象和集合
参数一:sql语句 参数二:RowMapper,是接口,返回不同类型数据,使用这个接口里面的实现类完成数据的封装 参数三:sql语句参数值
@Override public Book findBookInfo(String id) { String sql="select * from t_book where userId=?"; Book book=jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Book>(Book.class),id); return book; }
@Override public List<Book> findAllBook() { String sql="select * from t_book"; List<Book> bookList=jdbcTemplate.query(sql,new BeanPropertyRowMapper<Book>(Book.class)); return bookList; }
4.7 批量操作
批量添加:
参数一:sql语句 参数二:List集合,添加的多条记录数据
//批量添加 @Override public void batchAdd(List<Object[]> batchArgs) { String sql="insert into t_book values(?,?,?)"; int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs); System.out.println(Arrays.toString(arr));//影响的行数 } //测试 //批量添加 List<Object[]> batchArgs=new ArrayList<>(); Object[] o1={"3","java","a"}; Object[] o2={"4","sql","b"}; Object[] o3={"5","c++","c"}; batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); //调用批量添加 bookService.batchAddBook(batchArgs);
批量修改:
public void batchUpdate(List<Object[]> batchArgs) { String sql="update t_book set userName=?,userStatus=? where userId=?"; int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs); System.out.println(Arrays.toString(arr));//影响的行数 } //测试 List<Object[]> batchArgs=new ArrayList<>(); Object[] o1={"java0909","a3","3"}; Object[] o2={"sql1212","b4","4"}; Object[] o3={"c++3434","c5","5"}; batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); //调用批量添加 bookService.batchUpdateBook(batchArgs);
批量删除:
public void batchDelete(List<Object[]> batchArgs) { String sql="delete from t_book where userId=?"; int[] arr=jdbcTemplate.batchUpdate(sql,batchArgs); System.out.println(Arrays.toString(arr)); }
5. 事务操作
事务的四个特性:原子性,一致性,隔离性,持久性
1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。
2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
4、持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。
5.1 搭建环境
针对转账场景的环境分析:
创建Bank表
设计Dao DaoImpl Service Bank_bean
package com.wang.transaction; public interface BankDao { public void add(); public void reduce(); } ---------------------------------------------------------------------------------- package com.wang.transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class BankDaoImpl implements BankDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public void add() { String sql = "update bank set money=money+? where name=?"; jdbcTemplate.update(sql,100,"mary"); } @Override public void reduce() { String sql = "update bank set money=money-? where name=?"; jdbcTemplate.update(sql,100,"tom"); } } ------------------------------------------------------------------------- package com.wang.transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BankService { @Autowired private BankDao bankDao; public void accountMoney(){ bankDao.reduce(); bankDao.add(); } } ----------------------------------------------------------------------------- <?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 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.wang"></context:component-scan> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--配置数据库连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${prop.url}"></property> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="username" value="${prop.username}"></property> <property name="password" value="${prop.password}"></property> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean> </beans>
5.2 事务操作的引入
事务一般添加在service(逻辑业务)层
Spring进行事务管理的操作方式有两种:编程式和声明式(常用)
声明式事务管理:
-
基于注解(常用)和xml
-
在Spring进行声明式事务管理,底层使用AOP原理
Spring事务管理API:
-
提供了一个接口,代表事务管理器,此接口针对不同框架提供了不同的实现类
-
PlatformTransactionManager
-
开启事务
-
业务操作
-
无异常提交
-
异常回滚
5.3 注解声明式
-
配置文件中配置事务管理器
-
开启事务注解
引入命名空间tx
<!--开启事务注解--> <tx:annotation-driven transaction-manager="tansactionManager"></tx:annotation-driven>
-
在service类的方法上添加事务注解
-
如果添加到类上,则表示此类所有方法都添加事务
-
@Service @Transactional public class BankService {
管理参数配置
propagation(事务传播行为)
(1)Propagation.REQUIRED
如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。
-
多个事务方法直接进行调用,这个过程中事务是如何进行管理的
-
比如有一个事务方法调用了无事务的方法
-
@Service //@Transactional @Transactional(propagation = Propagation.REQUIRED) public class UserService { }(2)Propagation.SUPPORTS
-
如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。
-
(3)Propagation.MANDATORY
如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。
-
(4)Propagation.REQUIRES_NEW
-
重新创建一个新的事务,如果当前存在事务,延缓当前的事务。
-
(5)Propagation.NOT_SUPPORTED
以非事务的方式运行,如果当前存在事务,暂停当前的事务。
-
(6)Propagation.NEVER
-
以非事务的方式运行,如果当前存在事务,则抛出异常。
-
(7)Propagation.NESTED
如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。
-
isolation(事务隔离级别)
-
解决事务的隔离性
-
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
-
避免脏读,不可重复读,幻读
-
-
timeout(超时时间)
-
事务需要在一定时间内提交,否则会进行回滚,默认值是-1,设置时间以秒为单位
-
-
readOnly(是否只读)
-
默认false,表示CRUD都可以进行
-
设置为true后,只能查询
-
-
rollbackFor:回滚
-
设置查询哪些事务异常需要回滚
-
-
noRollbackFor:不回滚
-
设置查询哪些事务异常不需要回滚
-
5.4 xml配置文件方式
-
配置事务管理器
-
配置通知
-
配置切入点和切面
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns: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"> <!--开启组件扫描--> <context:component-scan base-package="com.wang"></context:component-scan> <!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!--配置数据库连接池--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="${prop.url}"></property> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="username" value="${prop.username}"></property> <property name="password" value="${prop.password}"></property> </bean> <!--JdbcTemplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean> <!--1.创建事务管理器--> <bean id="tansactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入数据源--> <property name="dataSource" ref="dataSource"></property> </bean> <!--2.配置通知--> <tx:advice id="txadvice" > <tx:attributes> <tx:method name="accountMoney" propagation="REQUIRED"/> <!--以count开头的方法都配置 <tx:method name="acount*"></tx:method> --> </tx:attributes> </tx:advice> <!--2.配置切入点和切面--> <aop:config > <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.wang.transaction.BankService.*(..))"/> <!--配置切面--> <aop:advisor advice-ref="txadvice" pointcut="pt"/> </aop:config> </beans>
5.5 完全注解声明式事务管理
使用配置类替代xml配置文件
package com.wang.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.TransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.activation.DataSource; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Properties; @Configuration//配置类说明 @ComponentScan(basePackages = "com.wang")//开启扫描 @EnableTransactionManagement//开启事务 public class TxConfig { //创建数据库连接池 @Bean public DruidDataSource getDruid() throws IOException { DruidDataSource DataSource = new DruidDataSource(); Properties properties = new Properties(); properties.load(new FileInputStream("src\\jdbc.properties")); DataSource.setDriverClassName(properties.getProperty("prop.driverClass")); DataSource.setUrl(properties.getProperty("prop.url")); DataSource.setUsername(properties.getProperty("prop.username")); DataSource.setPassword(properties.getProperty("prop.password")); return DataSource; } //创建Jdbc模板 @Bean//IOC容器中已经存在DataSource对象,直接声明类型就可以得到该对象 public JdbcTemplate getJdbcTem(DruidDataSource DataSource){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(DataSource); return jdbcTemplate; } //创建事务管理器 @Bean public DataSourceTransactionManager getTransationMan(DruidDataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } } -------------------------------------------------------------------------------------- package com.wang.transaction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional public class BankService { @Autowired private BankDao bankDao; public void accountMoney(){ bankDao.add(); bankDao.reduce(); } }