Spring开源框架
(一)Spring简介
1.轻量化开源框架
2.解决企业应用开发的复杂性,降低难度
3.Spring的两个核心部分:IOC 和 Aop
1. IOC:控制反转
把创建对象的过程交给spring管理
2. Aop:面向切面
不修改源代码进行功能增强
3.Spring特点
(1)方便解耦,简化开发
(2)Aop编程支持
(3)方便程序的测试
(4)方便和其他框架整合
(5)方便进行事务操作
(6)降低API开发难度
(二)入门小案例
1.下载Spring资源文件
最新5.29大概80多mb,链接:
选 spring-5.2.9.RELEASE-dist.zip 这个文件,下载比较慢的话可以复制链接用迅雷下载,下载好解压:
2.选取需要的jar包
小案例需要四个基础的jar包
都可以在解压好的libs中找到,commons-logging需要自行下载
3.打开IDEA创建Java 项目
打开idea创建普通的项目,将上面5个jar包导入到项目并添加环境变量
创建一个简单的User类:
package com.bgu.edu;
public class User {
public void add(){
System.out.println("add-------");
}
}
在src目录下,创建spring配置文件,new ---------> XML Configuration File -------> Spring config 起个名字叫bean1
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置User对象-->
<bean id="user" class="com.bgu.edu.User"></bean>
</beans>
添加
4.创建测试类
新建pakage:test 在包内创建测试类TestSpring.class
package test;
import com.bgu.edu.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TeatSpring {
@Test
public void testAdd(){
//加载Spring配置文件
ApplicationContext context=
new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
//运行User的构造方法
System.out.println(user);
user.add();
}
}
这里使用@Test会报错,点右面感叹号选第一个推荐方式,会自动导入:org.junit.Test 这个包,右键运行即可:
运行结果:
com.bgu.edu.User@27808f31
add-------
Process finished with exit code 0
(三)IOC
0.IOC 概念和原理
- 什么是IOC:控制反转,最常见的方式叫依赖注入。把创建对象和对象之间的调用过程交给Spring进行管理
- 使用IOC的目的:为了耦合度降低
- 做入门案例就是IOC实现
1.IOC 底层原理
xml解析技术、工厂模式、反射
class UserFactory { public static UserDao getDao(){ String classVlaue = class属性值;//1.xml解析得到class Class clazz = Class.forName(classValue);//2.通过反射创建对象 return (UserDao) clazz.newInstance(); } }
2.IOC 接口(BeanFactory)
- IOC 思想基于 IOC容器底层就是对象工厂
Spring 提供了IOC容器的实现方式(两个接口)
(1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提供开发人员使用
特点:加载配置文件时不会创建对象,在获取对象(使用)才会创建对象 User user = context.getBean("user",User.class)
(2)ApplicationContext:BeanFactory的子接口,提供更多更强大的接口。一般由开发人员使用
特点:加载配置文件的时候就会把配置文件里的对象进行创建
3.IOC 操作Bean管理
什么是Bean 管理
(0)Bean管理是指两个操作
(1)Spring 创建对象
(2)Spring 注入属性
4.IOC 操作Bean管理(基于xml)
<bean id="user" class="com.bgu.edu.User"></bean>
在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
(1)bean 标签里有很多属性
- id属性:唯一标识
- class属性:类全路径(包类路径)
- name属性:与id类似,name可以使用特殊字符,早期为strues1提供
(2)创建对象时,默认执行无参构造方法
基于xml方式注入属性
DI:依赖注入,就是注入属性
第一种方式:使用set方法进行中注入
首先,创建一个对象
package com.bgu.edu; /** * 演示使用set方法注入属性 */ public class Book { //创建基本属性 private String bname; private String bauthor; //创建属性对象的set方法 public void setBname(String bname) { this.bname = bname; } public void setBauthor(String bauthor) { this.bauthor = bauthor; } }
然后配置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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置Book对象--> <bean id="book" class="com.bgu.edu.Book"> <!--使用property完成属性注入 name:类里的属性名称 value:向属性注入的值 --> <property name="bname" value="已经近"></property> <property name="bauthor" value="哈哈哈"></property> </bean> </beans>
第二种方式:有参构造方法进行注入
首先,创建一个对象
package com.bgu.edu; /** * 使用有参数方法构造注入 */ public class Orders { //属性 private String oname; private String address; //有参构造方法 public Orders(String oname, String address) { this.oname = oname; this.address = address; } @Override public String toString() { return "Orders{" + "oname='" + oname + '\'' + ", address='" + address + '\'' + '}'; } }
然后配置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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="orders" class="com.bgu.edu.Orders">
<constructor-arg name="oname" value="电脑"/>
<constructor-arg name="address" value="中国"/>
</bean>
</beans>
```
spring配置简化:使用p名称空间注入
```xml
xmlns:p = "http://www.springframework.org/schema/p"
```
```xml
<bean id="orders" class="com.bgu.edu.Orders" p:bname="高等数学" p:bauthor="高同学"> </bean>
```
5.IOC 操作Bean管理(基于注入其他属性)
字面量
- null值
<property name="bname" > <null/> </property>
- 属性值包含特殊夫符号(转义 < >)
<property name="bname" > <value> <![CDATA[这里写带特殊的字符]]> </value> </property>
2.注入属性 - 外部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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- service和到对象的创建--> <bean id="userService" class="server.UserService"> <!--注入userDao对象 name属性,类里面属性名称 ref属性:创建userDao对象bean标签的id值 --> <property name="userDao" ref="userDaoImpl"></property> </bean> <!-- 注意 UserDao是接口,这里要写接口的实现类 也就是UserDaoImpl --> <bean id="userDaoImpl" class="dao.UserDaoImpl"></bean> </beans>
3.注入属性 - 内部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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--内部 Bean--> <bean id="emp" class="bean.Emp"> <property name="ename" value="李逵"></property> <property name="gender" value=" 男"></property> <property name="dept" > <bean id="dept" class="bean.Dept"> <property name="dname" value="行政部"></property> </bean> </property> </bean>
### 6.IOC 操作Bean管理(xml注入集合属性)
1. 注入数组类型属性
2. 注入List集合类型属性
3. 注入Map集合类型属性
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="stu" class="edu.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 key="PHP" value="php"/>
</map>
</property>
<property name="sets" >
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>
</bean>
4. 在集合里面设置对象
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="stu" class="edu.Stu">
<property name="courseList">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean id="course1" class="edu.Course">
<property name="cname" value="Spring 5"></property>
</bean>
<bean id="course2" class="edu.Course">
<property name="cname" value="MyBites"></property>
</bean>
5. 把集合注入提取到公共部分
- 在spring配置文件添加命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util = "http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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="book" class="edu.Book">
<property name="list" ref="booklist"></property>
</bean>
</beans>
```
7.IOC 操作 Bean 管理(FactoryBean)
- Spring 有两种 bean ,一种普通bean,一种factorybean
- 普通bean:在配置文件中定义的bean类型就是返回类型
- 工厂bean:在配置文件中定义的bean类型可以不是返回的bean类型
8.IOC 操作 Bean 管理(bean作用域)
- 在spring里面,设置创建bean实例是单实例还是多实例
- 在spring里面,默认情况下是单实例对象
- 如何设置单实例还是多实例:scope
- scope是属性值:singleton(单实例)、prototype(多实例)
- singleton(单实例):加载spring时,就会创建多实例对象
- prototype(多实例):不是在加载spring创建对象,在调用getBean时才会创建的对象
9.IOC 操作 Bean 管理(bean 生命周期)
- 生命周期:从对象创建和销毁的过程
bean生命周期:
- 通过构造器创建Bean实例(无参构造方法)
- 为bean的属性设置属性值和对其他bean引用(调用set方法)
- 调用bean的初始化方法(需要进行配置初始化的方法)
- bean可以使用了
- 当容器关闭时,调用bean的销毁方法(需要进行配置销毁方法)
10.IOC 操作 Bean 管理(xml自动装配)
什么是自动装配
根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值填入
- 实现方式:bean标签属性:autowire,配置自动装配 autowire有两个属性:byName 根据属性名注入,注入值bean的id值和类属性名称一样 byType:根据属性类型注入
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--自动装配--> <bean id="emp" class="autowire.Emp" autowire="byName"></bean> <bean id="dept" class="autowire.Dept"></bean> </beans>
11.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 http://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/userdb"></property> <property name="username" value="root"></property> <property name="password" value=""></property> </bean> </beans>
引入外部属性文件配置数据库连接池
- 创建外部属性文件,properties格式文件,写数据库信息
prop.driverClassName = com.mysql.jdbc.Driver prop.url = jdbc:mysql://localhost:3306/userdb prop.username = root prop.password =
把外部 properties 属性文件引入到spring配置文件中
- 引入context名称空间
- 在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 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.driverClassName}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.username}"></property> <property name="password" value="${prop.password}"></property> </bean> </beans>
12.IOC 操作 Bean 管理(基于注解)
什么是注解
- 代码里面特殊的格式,格式:@注解名称(属性名称=属性值,属性名称=属性值)
- 使用注解 :注解的作用在类的上面,方法上面,属性上面
- 使用注解目的:简化xml配置
Spring针对Bean管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
*上面四个注解功能是一样的,都可以用来创建bean实例
基于注解方式创建对象
- 第一步引入依赖:spring-aop-5.2.9.RELEASE.jar
第二步开启组件扫描:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:component-scan base-package="com.bgu.edu"></context:component-scan> </beans>
第三步
package com.bgu.edu; import org.springframework.stereotype.Component; //在注解里面value属性值可以省略不写 //如果不写 value 默认值是类的名称的首字母小写 //UserService----->userService @Component(value = "userService") public class UserService { public void add(){ System.out.println("add-----"); } }
基于注解方式实现属性注入
@AutoWired:根据属性类型进行自动装配
第一步:把service和dao对象创建,在servic和dao里添加创建对象注解
第二步:在service注入dao对象,在service类添加dao类型属性,在属性上使用注解
package com.bgu.edu; import com.bgu.edu.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; //在注解里面value属性值可以省略不写 //如果不写 value 默认值是类的名称的首字母小写 //UserService----->userService @Component(value = "userService") public class UserService { @Autowired private UserDao userDao; public void add(){ System.out.println("add-----"); } }
@Qualifier:根据属性名称进行注入
这个 @Qualifier注解的使用,需要和上面的@AutoWired配合使用:一个接口可能有多个实现类,@AutoWired无法准确找到我们需要的实现类,通过 @Qualifier指定我们具体实现众多实现类的哪一个
package com.bgu.edu.service; import com.bgu.edu.dao.UserDao; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; //在注解里面value属性值可以省略不写 //如果不写 value 默认值是类的名称的首字母小写 //UserService----->userService @Component(value = "userService") public class UserService { @Autowired @Qualifier(value = "userDaoImpl") private UserDao userDao; public void add(){ System.out.println("Service_add"); userDao.add(); } }
@Resource:可以根据类型注入,可以根据名称注入
package com.bgu.edu.service; import com.bgu.edu.dao.UserDao; import org.springframework.stereotype.Component; import javax.annotation.Resource; //在注解里面value属性值可以省略不写 //如果不写 value 默认值是类的名称的首字母小写 //UserService----->userService @Component(value = "userService") public class UserService { // private UserDao userDao; //@Resource //根据类型注入 @Resource(name = "userDaoImpl")//根据类名称注入 private UserDao userDao; public void add(){ System.out.println("Service_add"); userDao.add(); } }
@Value:注入普通数据类型属性
@Value(value = "abc") private String name;
5.完全注解开发
- 创建配置类:替代xml配置文件、
编写测试类
@Test public void test2(){ //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService",UserService.class); userService.add(); }
(四)AOP
0.AOP概念
什么是AOP?
- AOP:面向切面编程
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑之间的耦合度降低,提高程序的可重用性,同时提高开发效率
- 通俗描述:不通过修改源代码的方式,在主干功能里面添加功能
1.AOP底层原理
AOP底层使用动态代理
- 有两种情况的动态代理
第一种情况有接口,使用JDK动态代理
- 创建接口实现类的代理对象,实现功能增强
第二种情况没有接口,使用CGLIB动态代理
- 创建当前类的子类代理对象,实现功能增强
2.AOP(JDK动态代理)
使用 JDK动态代理,是使用Proxy类里面的方法创建代理对象
java.lang.Object
- java.lang.reflect.Proxy
调用 newProxyInstans方法,方法有三个参数
- 第一个参数:ClassLoader loder
- 第二个参数:增强方法所在的类,这个类实现的接口(可以写多个)
- 第三个参数:实现里面的接口 InvocationHandler,创建代理对象,写增强方法
JDK动态代理
- 创建接口,定义方法
- 创建接口实现类,实现方法
使用Proxy类,创建接口的代理对象
package com.bgu.edu; import java.lang.reflect.Array; 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) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; UserDaoImlp userDao = new UserDaoImlp(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1,2); System.out.println(result); } } //创建代理类对象 class UserDaoProxy implements InvocationHandler { //1.把创建是谁的代理对象,把谁传过来 //有参数的构造 private Object obj; public UserDaoProxy(Object obj) { this.obj = 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(obj, args); //方法之后 System.out.println("方法之后" + obj); return res; } }
3.AOP(术语)
连接点
- 类里面的拿些方法能被增强,这个方法就叫连接点
切入点
- 实际被真正增强的方法就是切入点
通知(增强)
- 实际增强的逻辑代码部分就是通知(增强)
有多种类型
- 1.前置通知
- 2.后置通知
- 3.环绕通知
- 4.异常通知
- 5.最终通知 :finally
切面
- 是动作
- 把通知应用加到切入点的过程
4.AOP操作(准备)
Spring框架中一般基于AspectJ 实现AOP操作
- 什么是AspectJ并不是Spring的组成部分,他是一个独立的AOP框架,一般把AspectJ和Spring一起使用,进行AOP操作
基于AspectJ 实现AOP操作
- 基于xml配置文件实现
- 基于注解方式实现(使用)
在项目的工程里引入依赖AspectJ
- spring-aspects-5.2.9.RELEASE.jar
- com.springsource.net.sf.cglib-2.2.0.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.6.4.RELEASE.jar
切入点的表达式
- 切入点表达式的作用:知道对哪个类的哪个方法进行加强
语法结构
- execution( [权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]))
举例1:
- 对 com.bgu.edu.UserDao 类里面的add方法进行增强
- execution(* com.bgu.edu.UserDao.add(..))
举例2:对 com.bgu.edu.UserDao 类里面的所有方法进行增强
- execution( com.bgu.edu.UserDao.(..))
举例3:对 com.bgu.edu包 里面的所有类的所有方法进行增强
- execution( com.bgu.edu.UserDao*.(..))
5.AOP操作(AspectJ注解)
创建类,在类里面定义方法
package com.bgu.edu.aopanno; //被增强的类 public class User { public void add(){ System.out.println("User_add"); } }
创建增强类(编写增强逻辑)
在增强类里面,创建方法,让不同的方法代表不同的通知类型
package com.bgu.edu.aopanno; public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
进行通知配置
- 在spring配置文件中,开启注解扫描
- 使用注解创建两个对象
增强的类上面添加注解:@Aspect
package com.bgu.edu.aopanno; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class UserProxy { //前置通知 public void before(){ System.out.println("before....."); } }
在spring配置文件生成代理
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.bgu.edu.aopanno"></context:component-scan> <!--开启Aspect生成代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
配置不同类型的通知
在增强类的利埃纳,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
package com.bgu.edu.aopanno; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class UserProxy { //前置通知 //@Before注解表示作为前置通知 @Before(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void before(){ System.out.println("before....."); } //最终通知 @After(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void afer(){ System.out.println("after......"); } //后置通知 @AfterReturning(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void aferReturning(){ System.out.println("AfterReturning......"); } @AfterThrowing(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void aferThrowing(){ System.out.println("AfterThrowing......"); } @Around(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
TestAopanno测试调用
package com.bgu.edu.test; import com.bgu.edu.aopanno.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestAop { @Test public void testAopanno(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add(); } }
相同切入点抽取
package com.bgu.edu.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.bgu.edu.aopanno.User.add(..))") public void pointdemo(){ } //前置通知 //@Before注解表示作为前置通知 @Before(value = "pointdemo()") public void before(){ System.out.println("before....."); } //最终通知 @After(value = "pointdemo()") public void afer(){ System.out.println("after......"); } //后置通知 @AfterReturning(value = "pointdemo()") public void aferReturning(){ System.out.println("AfterReturning......"); } @AfterThrowing(value = "pointdemo()") public void aferThrowing(){ System.out.println("AfterThrowing......"); } @Around(value = "pointdemo()") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前......"); proceedingJoinPoint.proceed(); System.out.println("环绕之后......"); } }
多个增强类可以设置优先级
在增强类的上面添加注解@Order(数值类型),数字越小优先级越高
package com.bgu.edu.aopanno; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Aspect @Order(value = 1) public class PersonProxy { @Before(value = "execution(* com.bgu.edu.aopanno.User.add(..))") public void before(){ System.out.println("PersonProxy_before....."); } }
(五) JDBCTemplate
0.什么是JdbcTemplate(概念理论)
- Spring框架对JDBC进行了封装,使用JdbcTemplate方便实现对数据库操作
准备工作
在原来的基础上引入相关jar
在spring配置中配置数据库连接池
<!--配置德鲁伊数据库连接池--> <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/userdb"></property> <property name="username" value="root"></property> <property name="password" value=""></property> </bean>
配置JdbcTemplate对象,注入
<!--JdbcTeplate对象--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入DataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
创建service类,创建dao类,在dao注入JdbdTemplate对象
- xml
<!--开启组件注解扫描--> <context:component-scan base-package="com.bgu.edu"></context:component-scan>
- Service
package com.bgu.edu; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class Srevice{ //注入dao @Autowired private Dao dao; }
- Dao实现类
package com.bgu.edu; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class DaoImpl implements Dao{ //注入jdbcTemplate @Autowired JdbcTemplate jdbcTemplate; }
1.JdbcTemplate 操作数据库(基本类)
对应数据库表创建实体类
编写service和dao
- 在dao里进行数据库的添加操作
调用jdbcTemplate对象里面的 update 方法实现添加操作
jdbcTemplate.update(String sql,Object ...args);
- 有两个参数
- 第一个参数:sql语句
- 第二个参数值:可变参数,设置sql语句中的值
package com.bgu.edu; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; @Repository public class DaoImpl implements Dao{ //注入jdbcTemplate @Autowired JdbcTemplate jdbcTemplate; //添加的方法 @Override public void add(User user) { //创建sql语句 String sql = "INSERT INTO t_user VALUES(?,?,?)"; //调用方法实现 Object[] args = {user.getUserId(),user.getUsername(),user.getUstatus()}; // int update = jdbcTemplate.update(sql,user.getUserId(),user.getUsername(),user.getUstatus()); int update = jdbcTemplate.update(sql,args); System.out.println(update); } }
测试类
package com.bgu.edu; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestDao { @Test public void testDao(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); UserService srevice = context.getBean("userService", UserService.class); User user = new User("001","张三","正常"); srevice.addUser(user); } }
2.JdbcTemplate 操作数据库(增删改查)
增加
//添加的方法 @Override public void add(User user) { //创建sql语句 String sql = "INSERT INTO t_user VALUES(?,?,?)"; //调用方法实现 Object[] args = {user.getUserId(),user.getUsername(),user.getUstatus()}; // int update = jdbcTemplate.update(sql,user.getUserId(),user.getUsername(),user.getUstatus()); int update = jdbcTemplate.update(sql,args); System.out.println(update); }
删除
//删除方法 @Override public void delete(User user) { //DELETE FROM 表名称 WHERE 列名称 = 值, String sql = "DELETE FROM t_user WHERE user_id=?"; int delete = jdbcTemplate.update(sql,user.getUserId()); System.out.println(delete); }
查询返回某个值
- 查询表里有多少条记录,返回的是某个值
使用 JdbcTemplate 实现查询返回某个值的代码
jdbcTemplate.queryForObject(String sql,Class<T> requiredType)
- 有两个参数
- 第一个参数:sql语句
- 第二个参数:返回类型的Class
@Override public int selectCount() { String sql = "SELECT COUNT(*) FROM t_user"; //如果返回值为String,第二个参数就是 String.class Integer count = jdbcTemplate.queryForObject(sql,Integer.class); return count; }
查询返回对象
- 场景:查询图书详情
JdbcTemplate 实现查询返回对象
jdbcTemplate.queryForObject(String sql,RowMapper<T> rowMapper, Object ...args)
- 有三个参数
- 第一个参数:sql语句
- 第二个参数:RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类进行数据封装
- 第三个参数:可变参数,设置sql语句中的值
@Override public User findUserInfo(String id) { String sql = "SELECT * FROM t_user WHERE user_id=?"; User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id); return user; }
查询返回集合
- 场景:查询图书列表分页
调用 JdbcTemplate 方法实现
jdbcTemplate.query(String sql,Class<T> requiredType)
- 有三个参数
- 第一个参数:sql语句
- 第二个参数:RowMapper,是接口,返回不同类型的数据,使用这个接口里面的实现类进行数据封装
- 第三个参数:可变参数,设置sql语句中的值
@Override public List<User> findAllUser() { String sql = "SELECT * FROM t_user"; List<User> userList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class)); return userList; }
数据库批量操作
- 批量操作:操作表里多条记录
JdbcTemplate 实现批量添加操作
jdbcTemplate.batchUpdate(String sql,List<Object[]> batchArgs)
- 两个参数
- 第一个参数:sql语句
- 第二个参数:List数组,添加多条记录数据
@Override public void batchAdd(List<Object[]> batchArgs) { String sql = "INSERT INTO t_user VALUES(?,?,?)"; int[] ints = jdbcTemplate.batchUpdate(sql,batchArgs); System.out.println(Arrays.toString(ints)); }
- 测试方法:
List<Object[]> batchArgs = new ArrayList<>(); Object[] o1 = {"8","java","正常"}; Object[] o2 = {"9","mysql","异常"}; Object[] o3 = {"10","php","正常"}; batchArgs.add(o1); batchArgs.add(o2); batchArgs.add(o3); userService.batchAdd(batchArgs);
(六)事务操作
0.事务概念
1.事务操作(搭建环境)
创建数据库表,添加记录
创建service,搭建dao ,完成对象创建和注入
- service注入dao,dao注入jdbcTemplate,在jdbcTemplate注入DataSource
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.bgu.edu"></context:component-scan> <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/userdb"></property> <property name="username" value="root"></property> <property name="password" value=""></property> </bean>
<!--JdbcTeplate对象-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--注入DataSource-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
```
//DAO类 @Repository public interface Dao { public void add(); public void reduce(); }
//Dao实现类 @Repository public class DaoImpl implements Dao{ @Autowired private JdbcTemplate jdbcTemplate; public void add() { String sql = "UPDATE t_account SET money = money-? WHERE username=?"; jdbcTemplate.update(sql,100,"lucy"); } public void reduce() { String sql = "UPDATE t_account SET money = money+? WHERE username=?"; jdbcTemplate.update(sql,100,"mary"); } }
//Service类 @Service public class DaoService { @Autowired private Dao dao; //转账操作 public void acountmoney(){ dao.reduce(); dao.add(); } }
public class TestDao { @Test public void money(){ ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); DaoService daoService = context.getBean("daoService",DaoService.class); daoService.acountmoney(); } }
- 上面的转账代码正常执行无问题,倒是如果在执行过程中出现异常
事务操作基本
public void acountmoney(){ try{ //开启事务 //进行业务操作 dao.reduce(); dao.add(); //模拟异常 int a = 0/100; //没有异常,提交事务 }catch (Exception e){ //出现异常,事务回滚 } }
2.事务操作(Spring事务管理介绍)
- 事务添加到JavaEE的三成结构里的Service层(业务逻辑层)
在Spring进行事务管理操作
- 有两种方式,编程式事务管理和声明式事务管理(使用)
声明式事务管理
- 基于注解方式
- 基于xml配置文件
- 在Spring进行声明式事务管理,底层使用AOP管理
Spring 事务管理API
提供一个接口,代表事务管理器,这个接口针对不同框架
3.事务操作(基于XML)
在配置文件中创建事务管理器
<!--创建事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
开启事务注解
引入第三方命名空间
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
开启事务注解
<!--开启事务注解--> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
在Service类上面或方法上面添加注解
- @Transactional,这个注解既可以添加到类上面,也可以添加到方法上面
- 如果把注解添加到类上面,这个类里面的所有方法都添加了事务
- 如果把注解添加到方法上面,为这个方法添加了事务
4.事务操作(声明式事务管理参数管理)
在service类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数