Title: JavaSpring框架使用学习 |
---|
Author: ychhh_ |
文章目录
Sping框架的概述
基本概述
-
框架概述:
-
javaSpring是轻量级的开源的JavbaEE框架
-
Spring可以解决企业开发的复杂性
-
Spring有两大核心部分:
- IOC:控制反转,把创建对象交给Spirng进行管理
- Aop:面向切面,不修改源代码的情况下进行功能的增强
-
-
Spring特点:
- 方便耦合,简化开发
- Aop编程支持
- 方便程序测试
- 方便和其他框架进行整合
- 降低API开发难度
spring认识
通过spring创建对象
public class test1 {
@Test
public void test(){
// 加载spring配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
//创建对象
User user = context.getBean("user",User.class);
System.out.println(user);
user.test();
}
}
创建spring的配置文件(床创建类的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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 配置对象的创建 --> <bean id="user" class="springTest1.User"></bean> </beans>
将spring的配置文件引入java文件
ApplicationContext context = new ClassPathXmlApplicationContext("springTest1\\bean1.xml");
类的创建
User user = context.getBean("user",User.class);
IOC模块
- IOC底层原理
- IOC接口(BeanFactory)
- IOC操作(基于XML / 注解)
概念和原理
- 什么是IOC
- 控制反转,把对象的创建和对象之间的调用过程,交给Sring进行处理
- 使用IOC的目的,为了耦合度的降低
- IOC的底层原理
- xml解析,工厂模式,java反射
IOC接口
- BeanFactory:
- IOC容器实现的基本接口,不提供给开发人员使用
- 在加载配置文件时不会创建对象
- ApplicationContext:
- BeanFactory接口的子接口,提供更强大的功能
- 在加载配置文件时就会创建对象
- 两个基本的实现类:
- ClassPathXmlApplicationContext():相对路径(使用ClassLoader加载)
- FileSystemPathXmlApplicationContext():绝对路径(使用InputStream加载)
IOC操作Bean管理操作
什么是Bean管理
- Bean管理指的是两个操作:
- Spring创建对象
- Spring注入属性
基于xml方式
-
基于xml的对象构造:
<bean id="user" class="springTest1.User"></bean> <!-- 默认调用无参构造函数 -->
- 在sprng的配置文件中使用bean标签,标签里添加对应的属性,就可以实现对象的创建
- 在bean中有很多属性,介绍常用的属性:
- id属性:唯一标识
- class属性:类的全路径
- name属性:可以完成和id属性相同的作用,和id属性唯一的区别为在name属性中可以添加特殊符号,而在id属性中不可以添加特殊符号
- 默认执行无参构造方法
-
基于xml的属性注入:
-
DI:依赖注入,注入属性
-
第一种注入方式:使用Set方法进行注入
<bean id="book" class="springTest1.Book"> <!-- 先有对象才有属性 --> <property name="bAuthor" value="YCH"></property> <property name="bName" value="diao"></property> </bean>
public class Book { public Book(){ } private String bName; private String bAuthor; public void setbName(String bName) { this.bName = bName; } public void setbAuthor(String bAuthor) { this.bAuthor = bAuthor; } public String getbName() { return bName; } public String getbAuthor() { return bAuthor; } }
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest1\\bean1.xml"); Book book = context.getBean("book",Book.class); System.out.println(book.getbAuthor() + " " + book.getbName()); }
-
第二中注入方式:使用有参构造方法进行注入
<!-- 属性注入 (有参构造方式方式) --> <bean id="book1" class="springTest1.Book"> <constructor-arg name="bAuthor" value="ych"></constructor-arg> <constructor-arg name="bName" value="ddd"></constructor-arg> <!-- <constructor-arg index="0" value="ddd"></constructor-arg> 也可以进行属性注入,此时index为有参构造的顺序 --> </bean>
@Test public void test3(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest1\\bean1.xml"); Book book = context.getBean("book1",Book.class); System.out.println(book.getbAuthor()); }
- Tips:若在一个xml配置文件中既是用了Set方式又使用了有参构造方式,配置文件的id需要为不同的ID
-
-
P名称空间注入:
<!-- 添加xml相关约束(p约束) --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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 https://www.springframework.org/schema/util/spring-util.xsd"> <!-- 配置对象的创建 --> <bean id="user" class="springTest1.User"></bean>
@Test public void test4(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest1\\bean1.xml"); Book book = context.getBean("book2",Book.class); System.out.println(book.getbAuthor()); }
-
基于xml的其他类型属性注入
-
属性值为空值:
<bean id="book3" class="springTest1.Book"> <property name="bName"> <null/> </property> </bean>
-
属性值中有特殊符号:
-
使用转义符:>,<
-
使用CDATA
<bean id="book4" class="springTest1.Book"> <property name="bName" > <value><![CDATA[<<北京>>]]></value> </property> </bean>
-
-
外部注入(属性为类的注入 / 外部bean):
<bean id="service" class="springTest2.UserService.Service"> <property name="user" ref="user"></property> </bean> <bean id="user" class="springTest2.UserDao.UserDaoImp"></bean>
@Test public void test1(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest2\\inject.xml"); UserDao user= context.getBean("service", Service.class).getUser(); System.out.println(user); }
-
内部注入:
<bean id="emp" class="springTest2.Emp.Emp"> <property name="name" value="ych"></property> <property name="dept"> <bean id="dept" class="springTest2.Dept.Dept"> <property name="name" value="666"></property> </bean> </property>
public class Dept { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } } public class Emp { Dept dept; String name; public void setDept(Dept dept) { this.dept = dept; } public void setName(String name) { this.name = name; } public Dept getDept() { return dept; } }
-
级联注入:
-
第一种方式和外部注入相似
-
给类属性的属性赋值:
- 前提:需要对属性的主类设置相应属性的get方法
<bean id="emp2" class="springTest2.Emp.Emp"> <property name="dept" ref="dept"></property> <property name="dept.name" value="cs"></property> </bean> <bean id="dept" class="springTest2.Dept.Dept"></bean>
@Test public void test3(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest2\\inject.xml"); Emp emp = context.getBean("emp2",Emp.class); System.out.println(emp.getDept().getName()); } public class Emp { Dept dept; String name; public void setDept(Dept dept) { this.dept = dept; } public void setName(String name) { this.name = name; } public Dept getDept() { return dept; } }
-
-
集合注入:
<bean id="stu" class="springTest3.Stu"> <property name="list"> <list> <ref bean="course1"></ref> <ref bean="course2"></ref> </list> </property> <property name="set"> <set> <value>666</value> <value>555</value> </set> </property> <property name="map"> <map> <entry key="java" value="spring"></entry> <entry key="math" value="666"></entry> </map> </property> </bean> <bean id="course1" class="springTest3.Course"> <property name="name" value="ml"></property> </bean> <bean id="course2" class="springTest3.Course"> <property name="name" value="db"></property> </bean>
@Test public void test1(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest3\\inject.xml"); Stu stu = context.getBean("stu",Stu.class); for(Course c : stu.list) System.out.println(c.name); for(String str : stu.map.keySet()) System.out.println(str + " " + stu.map.get(str)); }
Attention:
-
在类内使用collections的子类时,只能使用最抽象的类(list,set,map)只有这些类在xml有对应的标签
-
在xml文件中使用对应的标签(list,set,map(entry))
-
对于一般的字符串型value使用value标签即可进行注入
-
对于对象型value使用ref,利用类似外部注入的方式进行注入
-
-
将类(这里以list为例)公有化:
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="List"> <value>666</value> <value>777</value> <value>888</value> </util:list> <bean id="collect" class="springTest3.ListInjecter"> <property name="list" ref="List"></property> </bean>
Attention:
-
需要导入util对应的包:
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的标签内,直接添加value(若为String类型的数据)添加id属性
-
若为对象类的value则利用ref标签引入
-
在property的标签内,使用ref将公有化的标签的id进行引入
-
-
工厂Bean:
-
使创建的工厂类实现FactoryBean接口(not BeanFactoy)
-
实现接口内的函数
-
在getObject的函数内返回要实现的类对象
public class UserFactory implements FactoryBean<User> { @Override public User getObject() throws Exception { return new User(); } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } } public class User { }
<bean id="user" class="springTest4.UserFactory"></bean>
-
-
bean的默认单例性:
在spring中bean的管理默认为单例模式,即在任何位置使用的bean为同一个bean
对于bean的单例性的调节:
- 在xml的配置文件内进行调节
<bean id="user" class="springTest4.UserFactory" scope="singleton"></bean> <!-- 默认单例 --> <bean id="user" class="springTest4.UserFactory" scope="prototype"></bean> <!-- 设置多例 -->
- singleton和prototype的区别:
- 对于默认scope或者指定singleton为在加载xml配置文件时就创建对象
- 对于指定prototype为在调用getBean函数时才创建对象
-
bean的生命周期
-
生命周期:从对象创建到销毁的过程
-
bean生命周期(无后置处理器):
-
通过构造器创建bean实例(无参构造)
-
为bean的属性设置值和对其他bean的引用(调用set方法)
-
调用bean的初始化方法(需要配置初始化方法)
-
bean的使用
-
当关闭容器时,需要对bean进行销毁(需要配置销毁方法)
演示代码:
<bean id="order" class="springTest5.Order" init-method="initMethod" destroy- method="destroyMethod"> <property name="name" value="ych"></property> </bean>
public class Order { private String name; public void setName(String name) { this.name = name; } private void initMethod(){ System.out.println("order has createn!"); } private void destroyMethod(){ System.out.println("order has destroied!"); } }
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest5\\inject.xml"); Order order = context.getBean("order",Order.class); System.out.println("using!"); // 销毁创建的bean ((ClassPathXmlApplicationContext)context).close(); //只有ApplicationContext的实现类有close方法 }
Attention:
- 当在单例模式下可以用spring进行销毁
- 当在多例模式下不可用spring进行销毁
-
-
有后置处理器:
-
声明一个实现了BeanPostProcessor的类,并添加值配置文件
-
在同一个配置文件中的所有bean文件均可调用后置处理器方法:
public class BeanPostPro implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // 在构造对象之前调用 System.out.println("before construct!"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //在构造对象之后调用 System.out.println("after construct!"); return bean; } }
<bean id="order" class="springTest5.Order" init-method="initMethod" destroy-method="destroyMethod" scope="singleton"> <property name="name" value="ych"></property> </bean> <bean id="construct" class="springTest5.BeanPostPro"></bean>
-
-
自动装配(autowire):
- byName:需要bean的ID和待构造的Bean的属性名相同
- 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" 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="jdbc.properties"></context:property-placeholder> <!-- 进行属性注入 --> <bean id="jdbc" 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>
- 引入命名空间(context)
- 引入配置文件
- 进行属性注入
-
-
-
基于注解方式
-
spring提供的注解:
- @Component
- @Service
- @Controller
- @Respository
* 这四个注解的功能是一样的,都可以用来创建对象
-
使用注解创建Bean:
-
引入aop的jar包,注解的使用需要aop,jar的解释
-
在xml中声明需要扫描注解的类(开启组件扫描):
- 若需要多个类的解决方法:
- base-package参数后的类用逗号隔开
- 若这多个类在统一目录下,将其父目录加载到base-package中
- 若需要多个类的解决方法:
-
在指定类的上方添加注解(Component,Conyroller,Service,Respository之一):
- 若不添加value属性,则默认value为类名,且类的的一个字母小写,否则为指定的value值
-
在创建bean对象时和使用xml创建方法相同
<?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="springTest7"></context:component-scan> </beans>
@Component(value = "user") public class User { public void start(){ System.out.println("hello world!"); } }
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("springTest7\\scan.xml"); User user = context.getBean("user",User.class); user.start(); }
-
-
组件扫描的一些细节:
-
默认filter:对指定文件中的所有关键词注解进行扫描
-
指定filter:仅对指定的filter进行扫描 / 不扫描:
<!-- 指定扫描 --> <context:component-scan base-package="springTest7"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 指定不扫描 --> <context:component-scan base-package="springTest7" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
* **当为指定扫描时,需要将默认扫描(use-default-filters)改为false** * **当为指定不扫描时,无需设置**
-
-
基于注解方式的属性注入:
-
常用注解:
- @AutoWire:根据属性的类型进行自动注入
- @Qualifier:根据属性的名称进行注入
- @Resource:既可以根据类型注入也可以根据名称进行注入
- @Value:普通类型的注入
-
AutoWire:
- 按照类型进行注入,直接在指定属性上添加该注解即可(只能当指定的类型只存在一个时,当存在多个候选的类型时不能使用该方法进行属性注入)
-
Qualifier:
-
按照名称进行注入
-
使用Qualifier时必须在其上添加AutoWire注解,即两个注解同时使用
@Autowired // 必须先添加AutoWire注解,若无该注解则无法使用Qualifier @Qualifier(value = "user") private UserDao user;
-
-
Resource:
- 既可以根据类型进行注入,也可以根据指定的名称进行注入。
- 不是Spring包中的功能,是javax中的annoation的
- Spring不推荐
-
Value:
- 注入普通类型(非特殊对象类注入)
-
-
完全注解开发:
-
完全使用注解进行开发,完全不使用xml
-
步骤:
-
创建配置类并添加配置注解
-
加载配置类
-
创建bean对象
// 注解类 @Configuration @ComponentScan(basePackages = {"springTest9"}) public class Config { }
@Repository public class User implements UserDao{ @Override public void show() { System.out.println("666"); } }
@Service public class UserService { @Autowired private UserDao user; public void show(){ user.show(); System.out.println("777"); } }
@Test public void test(){ ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); // 此处改为Annotation的子实现类 UserService user = context.getBean("userService",UserService.class); user.show(); }
-
-
AOP模块
AOP基本概念
-
作用:使用AOP思想,可以使业务逻辑部分进行隔离,使业务逻辑的耦合度降低,提高了代码重用性,提升了开发效率
-
通俗说明:不通过修改源代码的方式修改程序的主干
-
底层原理:AOP底层使用动态代理:
- 两种情况的动态代理:
- 有接口的情况,使用JDK的动态代理
- 无接口的情况,使用CGLIB的动态代理
- 两种情况的动态代理:
-
术语:
-
连接点:
类中哪些方法可以被增强,哪些方法就称为连接点(候选方法)
-
切入点
类内实际被增强的方法称为切入点(实际增强方法)
-
通知(增强)
- 实际增强的逻辑部分被称为通知(增强)
- 通知有很多类型:
- 前置通知
- 后置通知
- 环绕通知
- 异常通知(exception)
- 最终通知(finally)
-
切面
把通知应用到切入点的过程称为切面
-
JDK动态代理
Class Proxy
-
from:Java.lang.reflect.Proxy
-
some methods:
-
static Obcejct newProxyInstance(ClassLoader loader,类<?>[] interfaces ,InvocaionHandler h):
parameters:
- loader:类加载器
- interfaces:增强方法所在的类,这个类实现的接口,该接口可以为多个接口
- h(InvocationHandler):实现Invocatiion的接口,创建代理的对象,实现对象增强的部分
public class JDKProxy { public static void main(String[] args) { Class []interfaces = {UserDao.class}; UserDao user = new UserDaoImpl(); UserDao user1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() { private Object obj = user; public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("hello"); Object res = method.invoke(obj,args); System.out.println("world"); return new Integer(6); } }); System.out.println(user1.intInter(1,2)); } }
-
AOP操作(准备)
-
Spring框架一般是基于AspectJ实现的AOP操作:
-
什么是AspectJ:
AspectJ不是Spring的组成部分,独立的AOP框架,一般把AspectJ和Spring一起使用,进行AOP操作
-
基于AspectJ实现AOP操作
-
-
切入点表达式:
-
切入点表达式的作用:知到对类内的哪个方法进行增强
-
语法结构:
execution(【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】))
-
举例说明:
说明:
- *代表所有的权限
- 返回类型可以省略
- .*代表其中的所有
- 参数列表用…进行代替
-
对指定类的指定方法做增强:
excution(* spirngTest8.User,add(…))
-
对指定类的所有方法做增强:
excution(* sprintTest8.User.*(…))
-
对指定包的所有类的所有方法做增强:
excution(* springTest8..(…))
-
基于注解的AspectJ的AOP操作(推荐使用方法)
-
使用xml文件进行配置:
<?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="sprintTest12"></context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> </beans>
-
使用配置类进行AOP操作
@Configuration @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class}) @EnableAspectJAutoProxy(proxyTargetClass = true) // 进行AOP配置 public class Config { }
-
配置Proxy类
@Component @Aspect //声明为AOP切口代理 public class OrderProxy { @Before(value = "execution(* sprintTest12.Order.add(..))") void before(){ System.out.println("world"); } }
-
ATTENTION:
在进行aop的引入时,需要将proxy-target-class声明为TRUE
<tx:annotation-driven transaction-manager=“transactionManager”
proxy-target-class=“true”/>
注意:proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。如果proxy-target-class 属性值被设置为false,那么基于类的代理将起作用(这时需要cglib库)。如果proxy-target-class属值被设置为true,那么标准的JDK 基于接口的代理将起作用。即使你未声明 proxy-target-class=“true” ,但运行类没有继承接口,spring也会自动使用CGLIB代理。
高版本spring自动根据运行类选择 JDK 或 CGLIB 代理
-
执行顺序:
无异常情况:
around before…
before
Method
around after
after…
after returning…有异常情况:
around before…
before
after…
throwing -
综上总结:
- @before 前置通知
- @after 最终通知
- @afterReturning 后置通知
- @around 环绕通知
- @afterThrowing 异常通知
-
相同切入点抽取:
-
对相同的execution进行抽取,并合并使用
-
方法:
-
构建切入点函数
-
填充
@Pointcut(value = "execution(* springTest13.Order.show(..))") // 构切入点函数 void pointCutDemo(){} // 利用切入点函数进行填充 @Before(value = "pointCutDemo()") void before(){ System.out.println("before"); } @After(value = "pointCutDemo()") void after(){ System.out.println("after.."); } @AfterReturning(value = "pointCutDemo()") void afterReturning(){ System.out.println("after returning.."); } @Around(value = "pointCutDemo()") void round(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("around before.."); proceedingJoinPoint.proceed(); System.out.println("around after"); } @AfterThrowing(value = "pointCutDemo()") void afterThrow(){ System.out.println("throwing"); }
-
-
-
如果一个切入点使用多个代理的增强方法,如需要自定义设置增强的先后顺序,则在代理类的上增加主机注解 — @Order(value = 1…)
- 若value的值越小则优先级越高
-
完全注解开发:
@Configuration @ComponentScan(basePackageClasses = {Order.class, OrderPorxy.class}) @EnableAspectJAutoProxy(proxyTargetClass = true) public class Config { }
基于xml文件的AspectJ的配置方式
<?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
">
<bean id="user" class="springTest12.UserDaoImpl"></bean>
<bean id="userProxy" class="springTest12.UserProxy"></bean>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<aop:config>
<aop:pointcut id="p" expression="execution(* springTest12.UserDao.show(..))"/>
<aop:aspect ref="userProxy" order="1">
<aop:before method="before" pointcut-ref="p" ></aop:before>
</aop:aspect>
</aop:config>
</beans>
JDBCTemplate模块
JDBCTemplate基本概念
- 什么是JDBCTemplate:Spring对JDBC进行了封装,使用JDBCTemplate方便对数据库进行操作
- 添加相关依赖jar包
JDBCTemplate相关配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<context:component-scan base-package="springTest14"></context:component-scan>
<util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<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>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
-
对于其余部分为:
JDBCTemplate -> Dao -> Service
-
tips:针对MYSQL的URL形式
jdbc:mysql://localhost:/
利用JDBCTemplate进行(增删改)操作
@Component
public class CustoemrDaoImpl implements CustomerDao{
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(Customer cus) {
String sql = "insert into customers (id,name,email) values (?,?,?);";
int update = jdbcTemplate.update(sql,cus.getId(),cus.getName(),cus.getEmail());
System.out.println(update);
}
}
//`id``name``email``birth``photo``test`
public class Customer {
private int id;
private String name;
private String email;
private String birth;
private String photo;
private String test;
public Customer(int id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getBirth() {
return birth;
}
public String getPhoto() {
return photo;
}
public String getTest() {
return test;
}
public void setEmail(String email) {
this.email = email;
}
public void setBirth(String birth) {
this.birth = birth;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public void setTest(String test) {
this.test = test;
}
}
public interface CustomerDao {
void add(Customer cus);
}
@Component
public class Service {
@Autowired
private CustomerDao customer;
public void addCustomer(Customer cus){
customer.add(cus);
}
}
@Test
public void test(){
ApplicationContext context =
new ClassPathXmlApplicationContext("springTest14\\config.xml");
Service s = context.getBean("service",Service.class);
s.addCustomer(new Customer(1234,"ych","132@"));
}
利用JDBCTemplated对数据库进行查询操作
-
实现集合函数的查询
利用JDBCTemplate封装的queyForObject函数,返回单个值
- 参数解析:
- 第一个参数:sql语句
- 第二个参数:返回的对象类型的class
@Override public void selectSet(Customer cus) { String sql = "select count(*) from customers"; Integer res = jdbcTemplate.queryForObject(sql,Integer.class); System.out.println(res); }
- 参数解析:
-
实现单一对象的查询
- 参数解析:
- 第一个参数:sql语句
- 第二个参数:
- 实现类RowMapper的接口的类(ex:BeanPropertyRowMapper)
- 模板类别为数据库返回类型的类别
- 第三个参数:填充参数
- 此方法的返回结果为一个查询的实现类
@Override public void getTuple(String name) { String sql = "select * from customers where name=?;"; Customer cus = jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<Customer>(Customer.class),name); System.out.println(cus.getName()); }
- 参数解析:
-
实现对集合的查询
-
quert参数解析
- 第一个参数:sql语句
- 第二个参数:RowMapper的接口实现类
- 第三个参数:填充字符
-
使用list进行容纳
@Override public void findTuples() { String sql = "select * from customers;"; List<Customer> customerList = jdbcTemplate.query(sql,new BeanPropertyRowMapper<Customer>(Customer.class)); for(Customer cus : customerList) System.out.println(cus.getName()); }
-
利用JDBCTemplate实现批量操作
-
批量增加
一个Object数组对象为一个元组,一个Objecr对象为一个属性
@Override public void addBatch(List<Object[]> list) { String sql = "insert into customers (id) values (?);"; int res[] = jdbcTemplate.batchUpdate(sql,list); System.out.println(Arrays.toString(res)); }
-
删改同理
利用JBDCTemplate实现事物管理
-
什么是事物:
事物是数据库操作的基本单元,逻辑上的一组操作
-
事物的基本性质(ACID):
- 原子性
- 一致性
- 分离性
- 持久性
-
Attention:
- 事物一般添加到Service层(WEB层,Service层,Dao层)
-
事物管理的一般方法:
- 编程式事物管理(不推荐)
- 声明式事物管理**(底层使用了AOP的模式)**:
- xml方式
- 注解方式
基于注解的事务管理
-
实现方法:
-
引入tx的命名空间
-
声明事物控制器的bean模块,并注入dataSource
-
通过事物控制器打开注解驱动
-
在事物类上或事物的方法上添加事物注解
<?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:tx="http://www.springframework.org/schema/tx" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <context:component-scan base-package="springTest15"></context:component-scan> <util:properties id="prop" local-override="true" location="jdbc.properties"></util:properties> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="#{prop.url}"></property> <property name="username" value="#{prop.username}"></property> <property name="password" value="#{prop.password}"></property> <property name="driverClassName" value="#{prop.driverClassName}"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> / <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven> </beans> <!-- url=jdbc:mysql://localhost:3307/test username=root password=ych3362632 driverClassName=com.mysql.jdbc.Driver -->
@Component @Transactional public class UserService { @Autowired private UserDao customer; private void addMoney(String name,int m){ customer.addMoney(name,m); } private void relasMoney(String name,int m){ customer.relasMoney(name,m); } public void getPostMoney(String name1,String name2,int m){ addMoney(name2,m); int e = 10 / 0; relasMoney(name1,m); } }
-
-
声明式事物管理参数配置
-
propgation:传播行为
-
ioslation:事物的隔离级别:
-
【错误】脏读:一个未提交的事物读取了另一个未提交的事物(当被读的事物发生了rollback则导致数据不正确)
-
【现象非问题】幻读:一个未提交的事物读取了另一个事物添加的数据
-
【现象非问题】不可重复读:一个未提交的事物读取了另一个事物已经提交的数据
设置隔离级别:
脏读 不可重复读 幻读 READ UNCOMMITTED(读未提交) √ √ √ READ COMMITTED(读已提交) × √ √ REPEATABLE READ(可重复读)【MySQL默认】 × × √ SERILIZABLE(串行化) × × × -
-
timeout:超时时间:
- 事物需要在一定的时间内进行提交,如果不提交则进行回滚
- 默认值-1(不超时),设置时间以秒为单位
-
readOnly:是否只读:
- readOnly默认值为false,可进行增删改查
- 若设置为true,则只能查询
-
rollbackFor:设置出现哪些异常进行回滚
-
noRollbackFor:设置出现哪些异常不进行回滚
-
基于xml的事物管理
-
基于xml文件的配置
<?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:tx="http://www.springframework.org/schema/tx" 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/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/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd "> <util:properties id="prop" location="jdbc.properties" local-override="true"></util:properties> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="#{prop.url}"></property> <property name="driverClassName" value="#{prop.driverClassName}"></property> <property name="password" value="#{prop.password}"></property> <property name="username" value="#{prop.username}"></property> </bean> <context:component-scan base-package="springTest16"></context:component-scan> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <tx:advice id="txadvice"> <tx:attributes> <tx:method name="getPostMoney" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pt" expression="execution(* springTest16.UserService.getPostMoney(..))"/> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"></aop:advisor> </aop:config> </beans>
完全注解开发
-
步骤:
- 创建配置类
- 填充配置函数
- 完成配置
@Configuration @ComponentScan(basePackages = {"springTest17"}) @EnableTransactionManagement public class Config { @Bean public DruidDataSource getDataSource(){ DruidDataSource dataSource = new DruidDataSource(); Properties prop = new Properties(); FileInputStream fis = null; try { fis = new FileInputStream("src\\jdbc.properties"); prop.load(fis); dataSource.setUrl(prop.getProperty("url")); dataSource.setUsername(prop.getProperty("username")); dataSource.setPassword(prop.getProperty("password")); dataSource.setDriverClassName(prop.getProperty("driverClassName")); } catch (IOException e) { e.printStackTrace(); }finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } return dataSource; } } @Bean public JdbcTemplate getJdbcTemplate(){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(getDataSource()); return jdbcTemplate; } @Bean public DataSourceTransactionManager getDataSourceTransactionManager(){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(getDataSource()); return dataSourceTransactionManager; } }
@Component public class UserDaoImpl implements UserDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public void show() { String sql = "select * from customers;"; List<User> list = jdbcTemplate.query(sql,new BeanPropertyRowMapper<User>(User.class)); for(User user : list) System.out.println(user.getName()); } }
补充
工厂模式
普通模式:
class UserService{
public void execute(){
User user = new User();
user.add();
}
}
class UserDao{
public void add(){
System.out.println("hello world!");
}
}
/*
该模式缺点:
UserService和User类的耦合度太高
需要利用工厂模式进行解耦合
*/
工厂模式:
class UserService{
public void execute(){
User user = UserFactory.getUserDao();
user.add();
}
}
//UserFatory使用工厂模式降低UserService和UserDao的耦合度
class UserFactory{
public static getUserDao(){
return new UserDao();
}
}
class UserDao{
public void add(){
System.out.println("hello world!");
}
}
/*
通过工厂模式,使得UserService和User的耦合度进一步降低(但是并未降到最低)
另外UserFactory和User的耦合度依然很高
*/
在工厂模式的情况下进一步解耦合
//利用反射进一步解耦合
class UserFactory{
public static UserDao getUserDao(){
String classValue = class属性值; //通过xml解析得到
Class clazz = Clazz.forName(classValue);
return (UserDao)clazz.newInstance();
}
}
注解
- 注解是代码的特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值…)
- 使用注解,注解作用在类上,方法上,属性上
- 使用注解的目的(在spring中),简化xml文件的配置
动态代理
-
有接口的动态代理(JDK动态代理)
- 通过实现接口类的方法来增强类的对象
-
无接口的动态代理(CGLIB动态代理)
-
通过实现子类的方法来增强类
-