轻量级开源javaee框架
解决开发复杂性
两大核心:IOC,Aop
IOC:控制反转,将对象创建交给spring进行管理
Aop:面向切面,不修改源代码进行功能增强
特点:
框架下载导入[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jcu8wPzV-1650025796628)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220319135557285.png)]
xml配置[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N5wKEKKV-1650025796629)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220319135612639.png)]
@Test
public void add(){
//加载配置文件(src下)
ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建对象
User user = context.getBean("User", User.class);
System.out.println(user);
user.add();
}
百度百科: 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做**依赖注入(Dependency Injection,简称DI**),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ho2usKzf-1650025796629)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220319140245899.png)]
对于两个类之间耦合度过高的问题:
IOC过程
配置xml
创建工厂类,
public static Object create(){
Object o=null;
//此处使用xml解析获取全类名
String classname="com.fate.spring5.User";
//反射获取对象
try {
Class clazz =Class.forName(classname);
o = clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
1,IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2,IOC容器的两种实现方式
BeanFactory:IOC容器的基本实现,通常是spring内部使用
加载配置文件的时候不会创建对象,在获取的时候才创建
ApplicationContext:BeanFactory的子接口,提供更多,更强大的功能
在加载配置文件的时候,就进行对象的创建
3,ApplicationContext实现类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qpJxq3uq-1650025796630)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220319144856834.png)]
FileSystemXmlApplicationContext:使用磁盘路径
ClassPathXmlApplicationContext:使用项目的类路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-abLFyoZY-1650025796631)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220319145523657.png)]
包含一些拓展方法
Bean管理
DI:依赖注入,就是注入属性
public class Book {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
'}';
}
}
<bean id="book" class="com.fate.spring5.Book">
<property name="name" value="差不多得了">
property>
bean>
Book book = context.getBean("book", Book.class);
System.out.println(book);
<bean id="order" class="com.fate.spring5.Order">
<constructor-arg name="name" value="默认订单">constructor-arg>
<constructor-arg name="address" value="默认地址">constructor-arg>
bean>
public class Order {
private String name;
private String address;
public Order() {
}
//必须存在有参数构造
public Order(String name, String address) {
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "Order{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
'}';
}
}
@Test
public void order(){
Order order = context.getBean("order", Order.class);
System.out.println(order);
}
xmlns:p="http://www.springframework.org/schema/p"
<bean id="bookTest" class="com.fate.spring5.Book" p:name="坂本真绫">bean>
@Test
public void p(){
Book bookTest = context.getBean("bookTest", Book.class);
System.out.println(bookTest);
}
<constructor-arg name="address" >
<null/>
constructor-arg>
<bean id="book" class="com.fate.spring5.Book">
<property name="name">
<value>
>]]>
value>
property>
bean>
创建两个类
在service中调用dao的方法
配置xml
<bean id="userService" class="com.fate.spring5.service.UserService">
<property name="userDao" ref="userDao"> property>
bean>
<bean id="userDao" class="com.fate.spring5.dao.UserDao"> bean>
@Test
public void outBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
两种方式
外部赋值
<bean id="emp" class="com.fate.spring5.bean.Emp">
<property name="name" value="lucy"> property>
<property name="gender" value="女"> property>
<property name="dept" ref="dept"> property>
bean>
<bean id="dept" class="com.fate.spring5.bean.Dept">
<property name="name" value="xdzn"> property>
bean>
内部赋值,内部类需要get方法
<bean id="emp" class="com.fate.spring5.bean.Emp">
<property name="name" value="lucy"> property>
<property name="gender" value="女"> property>
<property name="dept" ref="dept"> property>
<property name="dept.name" value="519"> property>
bean>
<bean id="dept" class="com.fate.spring5.bean.Dept"> bean>
类型定义
public class Student {
private String[] courses;
private List<String> list;
private Map<String, String> map;
private Set<String> set;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setSet(Set<String> set) {
this.set = set;
}
@Override
public String toString() {
return "Student{" +
"courses=" + Arrays.toString(courses) +
", list=" + list +
", map=" + map +
", set=" + set +
'}';
}
}
<bean id="student" class="collectiontype.Student">
<property name="courses" >
<array>
<value>数据结构 value>
<value>java value>
<value>python value>
array>
property>
<property name="list">
<list value-type="java.lang.String">
<value>高等数学 value>
<value>离散数学value>
list>
property>
<property name="map">
<map value-type="java.lang.String" key-type="java.lang.String">
<entry key="1" value="通用英语"> entry>
<entry key="2" value="大学物理"> entry>
map>
property>
<property name="set">
<set value-type="java.lang.String">
<value>寄 value>
<value> 狠狠的寄value>
<value> 寄麻了value>
set>
property>
bean>
提取list进行注入
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="teacher" class="collectiontype.Teacher">
<property name="list" ref="list"> property>
bean>
<util:list id="list">
<value> 1value>
<value> 12value>
<value> 134value>
<value> 1234value>
<value> 1111value>
util:list>
beans>
<bean id="myBean" class="factoryBean.Mybean"> bean>
public class Mybean implements FactoryBean<Courses> {
@Override
public Courses getObject() throws Exception {
Courses courses = new Courses();
courses.setName("差不多得了");
return courses;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("FactoryBeanTest.xml");
Courses courses = context.getBean("myBean", Courses.class);
System.out.println(courses);
}
在bean中可以设置bean是否是单例
默认情况下都是单例[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hcFOaZoj-1650025796632)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220321175948260.png)]
如何设置是否单例
scope属性:singleton(默认,表示单例)| |prototype:多实例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VN5C9eL0-1650025796633)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220321180120372.png)]
区别
singleton:单例,prototype多实例
当scope为singleton时,加载配置文件时就会创建实例对象,如果是prototype,在调用getBean时才会创建
其他属性
request:放在request域中
session:放在session域中
演示
<bean id="orders" class="beanlife.Orders" init-method="init" destroy-method="destroy">
<property name="name" value="我不知道哇"> property>
bean>
public class Orders {
private String name;
public Orders() {
System.out.println("对象创建了");
}
public void setName(String name) {
System.out.println("调用set方法");
this.name = name;
}
public void init(){
System.out.println("初始化方法");
}
public void destroy(){
System.out.println("销毁方法");
}
}
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beanlifeTest.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("获取到对象:"+orders);
//销毁
((ClassPathXmlApplicationContext)context).close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Fq8d0Fm-1650025796633)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220322081355772.png)]
其他(bean的后置处理器,总计七步)
<bean id="myBeanPost" class="beanlife.MyBeanPost"> bean>
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之前执行:postProcessBeforeInitialization");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("初始化之后:postProcessAfterInitialization");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DNEKNeHE-1650025796634)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220322085627828.png)]
根据指定的装配规则(属性名称或属性类型),spring自动将匹配的属性值进行注入
演示
<bean id="depts" class="autowire.Depts"> bean>
<bean id="emps" class="autowire.Emps" >
<property name="depts" ref="depts"> property>
bean>
直接显式配置数据库信息
<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="mzf200314"> property>
bean>
引入外部属性文件配置数据库连接池
<context:property-placeholder location="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>
简化xml配置
上述注解功能相同都能创建bean实例,不同的名称只是用于区分程序
引入aop.jar包
开启组件扫描
<context:component-scan base-package="fromZJ"> context:component-scan>
创建类,添加注解
@Service(value = "userService")
public class UserService {
public void add(){
System.out.println("userService add");
}
}
组件扫描细节配置
<context:component-scan base-package="fromZJ" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
context:component-scan>
<context:component-scan base-package="fromZJ">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
context:component-scan>
提供以下注解实现属性注入
@AutoWired:根据属性类型进行注入
@Qualifier:根据名称进行注入(需与@AutoWired一起使用–场景:一个接口存在多个实现类)
@Resource:二者皆可(来自javax包,java官方提供,spring不建议使用)
@Value:普通类型注入
/**
* Configuration:表示该类为配置类,替代xml配置文件
* ComponentScan:代替xml开启组件扫描
* @author m
*/
@Configuration
@ComponentScan(basePackages = {"config","dao","fromZJ"})
public class SpringConfig {
}
百度百科:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
图解AOP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N1ubCTnU-1650025796635)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220322210520446.png)]
底层使用动态代理
两种动态代理:
有接口:JDK的动态代理;
创建接口实现类的代理对象
无接口:CGLIB动态代理
创建当前类子类的代理对象
AOP(JDK动态代理)
创建Proxy对象,调用newProxyInstance方法,
三个参数
类加载器
代理类实现的接口们
实现InvocationHandler,创建代理对象,写增强的方法
AOP(术语)
连接点
可以被增强的方法
切入点
实际真正增强的方法
通知(增强)
实际增强的逻辑部分
多种类型:
切面
是动作,把通知应用到切入过程
I 一般基于AspectJ实现AOP操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yiSrkwc7-1650025796636)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220406193149563.png)]
II 两种方式进行实现
xml配置
注解(主要)
III 引入依赖
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KEGuEetX-1650025796636)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220406195029331.png)]
IV 依赖表达式
知道对哪个类里面的哪个方法进行增强
格式:
execution([权限修饰符] [返回类型] [全类名] [方法名] ([参数列表]))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75JD7JHN-1650025796637)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220406200916976.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fDaFngvH-1650025796638)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220406200949817.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m0IZa0eP-1650025796638)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220406201016627.png)]
创建bean
创建增强类
进行通知配置
@Configuration
@ComponentScan(basePackages = {"AOPANN"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class Config {
}
开启注解扫描
<context:component-scan base-package="AOPTEST1"> context:component-scan>
使用注解创建User和UserProxy
在增强类上增加注解
xml开启生成代理对象
<aop:aspectj-autoproxy> aop:aspectj-autoproxy>
配置不同类型通知
在增强类中,在作为通知方法的上面添加通知类注解,使用切入点表达式进行配置
对切入点进行抽取
@Component
@Aspect
public class UserProxy {
@Pointcut(value = "execution(* AOPTEST1.User.add(..))")
public void fuck(){
}
@Before(value = "fuck()")
public void before(){
System.out.println("before..");
}
@After(value = "fuck()")
public void after(){
System.out.println("after..");
}
@AfterReturning(value = "fuck()")
public void afterReturning(){
System.out.println("afterReturning..");
}
@AfterThrowing(value = "fuck()")
public void afterThrowing(){
System.out.println("afterThrowing..");
}
@Around(value = "fuck()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("before around..");
proceedingJoinPoint.proceed();
System.out.println("after around..");
}
}
多个增强类,设置优先级
@Order(1)
**概念: **Spring对jdbc进行了封装,方便对数据库的准备操作:
事务:事务是数据库操作的最基本单元,逻辑上一组操作,要么都成功,要么都失败
原子性(Atomicity):要么都成功,要么都失败
一致性(Consistency):事务前后数据完整性要保证一致
隔离性(Isolation):
隔离性是多个用户并发访问数据库时,数据库为每个用户开启的事务,不能被其他事务的操作数据所干扰,事务之间要相互隔离
持久性(Durability) – 事务提交
事务没有提交,恢复原状
事务提交,持久化到数据库
通常添加到service层
两种方式:编程式和声明式
声明式的两种实现方式:注解,xml配置
在spring进行事务管理的时候,底层使用了AOP
开辟命名空间
xmlns:tx="http://www.springframework.org/schema/tx"
开启事务注解
<tx:annotation-driven transaction-manager="manager"/>
添加注解(可以在方法上,也可以在类上)
@Transactional
事务管理参数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kq8Fbvc8-1650025796639)(C:\Users\m\AppData\Roaming\Typora\typora-user-images\image-20220412081856714.png)]
propagation:事务传播行为
支持当前事务:
不支持当前事务:
其它:
ioslation:事务隔离级别
事务的隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read-Uncommitted) | 是 | 是 | 是 |
不可重复读(Read-Committed) | 否 | 是 | 是 |
可重复读(mysql默认)(Repeatable-Read) | 否 | 否 | 是 |
串行化(Serializable) | 否 | 否 | 否 |
事务的并发问题
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
timedout:超时时间
超时就回滚(默认-1不会超时)
readonly:只读
读:查,写:增删改
默认false,可读可写
rollbackFor:回滚
出现哪些异常回滚
noRollbackFor:不回滚
出现哪些异常不回滚
配置事务管理器
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="manager">
配置通知
<tx:advice transaction-manager="manager" id="advice">
<tx:attributes>
<tx:method name="account*"/>
tx:attributes>
tx:advice>
配置切入点和切面
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.fate.service.impl.UserServiceImpl.accountMoney(..))"/>
<aop:advisor advice-ref="advice" id="adv" pointcut-ref="pt"/>
aop:config>
package com.fate.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.springframework.beans.factory.annotation.Qualifier;
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.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
@Configuration //声明配置类
@ComponentScan(basePackages = "com.fate") //开启组件扫描
@EnableTransactionManagement //开启事务
public class TxConfig {
@Bean
public DruidDataSource getDruidDataSource() {
DruidDataSource druidDataSource = null;
Properties properties = new Properties();
InputStream inputStream = null;
try {
inputStream = TxConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(inputStream);
druidDataSource=(DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
return druidDataSource;
}
@Bean
public JdbcTemplate getJdbcTemplate( DruidDataSource druidDataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(druidDataSource);
return jdbcTemplate;
}
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DruidDataSource druidDataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(druidDataSource);
return dataSourceTransactionManager;
}
}
@Test
public void test2(){
GenericApplicationContext genericApplicationContext = new GenericApplicationContext();
genericApplicationContext.refresh();
genericApplicationContext.registerBean(User.class,()->new User());
}
引入spring test包
@SpringJUnitConfig(locations = "classpath:JDBC.xml")
后面再补吧