1.Spring概念
1.Spring是轻量级开源的JavaEE框架
2.Spring可以解决企业应用开发的复杂性
3.Spring有两个核心部分:IOC和Aop
(1)IOC:控制反转,把创建对象过程交给Spring进行管理。
(2)Aop:面向切面,不修改源代码的进行功能增强。
4.Spring特点
(1)方便解耦,简化开发
(2)Aop编程支持
(3)方便程序测试
(4)方便和其他框架进行整合
(5)事务管理,降低api开发难度
<!--Spring核心基础依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.9</version>
</dependency>
<?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">
<!--把testDao对象的创建权交给Spring-->
<bean id="user" class="org.example.dao.User"></bean>
</beans>
//1.加载spring的配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//2.获取配置创建的对象
User user = context.getBean("user", User.class);
System.out.println(user);
user.add();
2.IOC容器
(1) IOC底层原理
IOC(概念和原理)
1.什么是IOC。
(1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。
(2)使用IOC的目的:为了耦合度的降低。
耦合度的理解:两个实体类之间的关系
2.IOC底层原理
xml解析、工厂模式、反射。
<bean id="dao" class="com.example.UserDao"></bean>
Class UserFactory{
public static UserDao getDao(){
String classValue = class属性值; //xml解析
Class class = Class.forName(classValue); //通过反射创建对象
return (UserDao)class.newInstance;
}
}
(2) IOC接口(BeanFactory)
1.IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
2.Spring提供IOC容器
(1).BeanFactory:IOC容器基本实现,是Spring内部的使用接口,开发一般不适用。
(2) ApplicationContext:BeanFactory接口的子接口 ,提供更多更强大的功能,一般由开发人员进行使用。
区别:BeanFactory加载配置文件时候不会创建对象,在获取对象才会去创建对象。ApplicationContext加载配置文件时候就会把在配置文件的对象进行创建
3.ApplicationContext接口
##### 1.什么是Bean管理 (1)Spring创建对象 (2)Spring注入属性 ##### 2.Bean管理操作有两种方式 (1)基于xml方式实现 (2)基于注解方式实现
(3)IOC操作Bean管理(基于xml)
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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--把testDao对象的创建权交给Spring--> <bean id="user" class="org.example.dao.User"></bean> </beans>
ps:创建对象时,默认执行无参数的构造方法
设置空值
特殊符号解决
2.注入属性
(1)DI:依赖注入,就是注入属性。
<!--set方法注入属性--> <bean id="book" class="org.example.pojo.Book"> <property name="name" value="abc"></property> <property name="author" value="Chalres"></property> </bean><!--有参构造属性--> <bean id="order" class="org.example.pojo.Orders"> <constructor-arg name="name" value="电脑"></constructor-arg> <constructor-arg name="address" value="China"></constructor-arg> </bean>
还可以用index代替name,代表有参构造的第i个参数。
p名称空间(了解即可)
注入属性-内部bean和级联赋值
<bean id="emp" class="org.example.pojo.Emp"> <property name="name" value="loucy"></property> <property name="gender" value="女"></property> <!-- 在内部嵌套对象注入 --> <property name="dept"> <bean id="dept" class="org.example.pojo.Dept"> <property name="name" value="安保部"></property> </bean> </property> </bean><bean id="emp" class="org.example.pojo.Emp"> <property name="name" value="loucy"></property> <property name="gender" value="女"></property> <!-- 在内部嵌套对象注入 --> <property name="dept" ref="dept"> </property> </bean> <bean id="dept" class="org.example.pojo.Dept"> <property name="name" value="安保部"></property> </bean>
注入集合
<property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property>
集合注入部分提取出来
1.在spring配置文件中引入名称空间util
1.Spring有两种类型bean,一种普通类型bean,另一种是工厂bean(Factory bean)
普通bean:在配置文件中定义bean类型就是返回类型。
工厂bean:在配置文件定义bean类型可以和返回类型不一样
(1)创建类,让这个类作为工厂bean,实现接口FactoryBean
(2)实现接口里面的方法,并定义返回bean类型。
public class MyBean implements FactoryBean<Course> { @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
bean的作用域
1.在Spring里面,默认情况下,bean是单实例对象,即从ApplicationContext获得的一直是一样地址的对象
<bean id="myBean" class="org.example.factorybean.MyBean" scope="prototype"></bean>
2.singleton和prototype区别
第一、singleton单实例,prototype多实例
第二、设置singleton环境时,加载spring配置文件时就会创建单实例对象。设置prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象
3.bean生命周期(bean后置处理器)
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
把bean实例传递bean后置处理器的方法
(3)调用bean的初始化方法(需要进行配置初始化的方法)
把bean实例传递bean后置处理器的方法
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时候,调用bean的销毁方法(需要配置销毁方法)
xml自动装配
1.什么是自动装配:根据指定装配规则,Spring自动将匹配的属性值进行注入。
<bean id="emp" class="org.example.pojo.Emp" autowire="byName"> </bean> <bean id="dept" class="org.example.pojo.Dept"></bean>
引入外部属性文件配置数据库连接池
<context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.userName}"></property> <property name="password" value="${prop.password}"></property> </bean>
在spring配置文件中引入配置文件信息
(4)IOC操作Bean管理(基于注解)
1.使用注解的目的:简化xml配置
2.Spring针对Bean管理中创建对象提供注解
@Component
@Service
@Controller
@Repository
基于注解方式的对象创建
1.引入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.9</version> </dependency>
2.组件扫描
<context:component-scan base-package="org.example"></context:component-scan>
use-default-filters:可以设置是否使用默认的扫描器
3.添加注解
基于注解的属性注入
1.@AutoWired
根据属性类型进行自动装配
2.@Qualifier
根据属性名称进行注入,要和上面@Autowired一起使用,可以具体指定注入哪个类型的属性
3.@Resource
可以根据属性类型进行自动装配,也可以根据属性名称进行注入。
4.@Value
可以注入普通类型的值
完全注解开发
1.创建配置类
2.加载配置类
@Configuration //作为配置类,替代xml文件
@ComponentScan(basePackages = {"org.example"})
public class SpringConfig {
}
3.Aop
1.概念
面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
通俗描述:不通过修改源代码方式添加新的功能,在主干功能里面添加新功能。
2.底层原理
1.AOP底层使用动态代理
代理的理解:Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。 更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。
按照代理的创建时期,代理类可以分为两种: 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 动态:在程序运行时运用反射机制动态创建而成。
(1)有两种情况的动态代理。
第一种,有接口的情况,使用jdk动态代理。
创建接口实现类代理对象,增强类的方法。
第二种 没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
2.实操
1.jdk动态代理,使用Proxy里面的方法
调用newProxyInstance方法
public class App { public static void main( String[] args ) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(App.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1,2); System.out.println(result); } } class UserDaoProxy implements InvocationHandler{ //增强的逻辑 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; } }
AOP术语
连接点:类里面可以增强的方法。
切入点:实际被真正增强的方法
通知(增强):
1.实际增强的逻辑部分称为通知
2.前置通知,后置通知,环绕通知,异常通知,最终通知
切面:把通知应用到切入点
AOP操作
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.7.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.0</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
1.Spring框架一般是基于AspectJ实现AOP操作
(1)ASpectJ不是Spring组成部分,独立AOP框架,一般将AspectJ和Spring框架一起使用进行AOP操作
2.切入点表达式
作用:知道对哪个类里面的方法进行增强
execution(* com,atguigu.dao.BookDao.*(..)) //星号表示任意
3.AOP操作(AspectJ注解)
1.在spring配置文件中,开启注解扫描
//可以直接用配置类实现 @Configuration @ComponentScan(basePackages={"com.atiguigu"} @EnableAspectJAutoProxy(proxyTargetClass=ture) public class ConfigAop{ }
2.使用注解创建User和UserProxy对象
3.在增强类上添加注解@Aspect
4.在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:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.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="org.example.aopanno"></context:component-scan> <!--开启AspectJ生成代理对象 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
@Component
@Aspect
public class UserProxy {
//前置通知
@Before(value = "execution(* org.example.aopanno.User.add(..))")
public void before(){
System.out.println("before");
}
@After(value = "execution(* org.example.aopanno.User.add(..))")
public void after(){
System.out.println("after......");
}
@AfterReturning(value = "execution(* org.example.aopanno.User.add(..))")
public void afterreturn(){
System.out.println("afterReturning......");
}
@AfterThrowing(value = "execution(* org.example.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("afterThrowing");
}
@Around(value = "execution(* org.example.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
System.out.println("环绕之前");
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
有多个增强类对同一个方法进行增强,设置增强类的优先级
用@Order注解来设置优先级
4.AOP操作(AspectJ配置文件)
了解即可,一般不用
<bean id="book" class="org.example.aopxml.Book"></bean> <bean id="bookProxy" class="org.example.aopxml.BookProxy"></bean> <!--配置aop增强--> <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* org.example.aopxml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config>
4.JdbcTemplate
1.概念和准备
什么是jdbcTemplate
spring框架对JDBC进行封装,方便对数据库进行操作
操作
1.导入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.9</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.3.9</version> </dependency>
2.在spring配置文件配置数据库连接池
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"></property> <property name="url" value="${prop.url}"></property> <property name="username" value="${prop.userName}"></property> <property name="password" value="${prop.password}"></property> </bean>
3.配置jdbcTemplate对象,注入DataSource
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <!--注入dataSource--> <property name="dataSource" ref="dataSource"></property> </bean>
4.通过jdbcTemplate在dao层操作数据库
@Repository public class BookDaoImpl implements BookDao{ @Autowired private JdbcTemplate jdbcTemplate; @Override public void add(Book book) { //1.创建sql语句 String sql = "insert into t_book values(?,?,?)"; //2.调用方法实现 int update = jdbcTemplate.update(sql, book.getUserId(), book.getUsername(), book.getUstatus()); System.out.println(update); //返回更新的数据条数 } }
JdbcTemplate操作数据库
query过程都可以进行数据类型自动转换,而且不仅仅按标准命名,还可以支持下划线分隔后拼接成驼峰式字符 完全轻量级. BeanPropertyRowMapper/ParameterizedBeanPropertyRowMapper ,如果PO和数据库模型的字段完全对应(字段名字一样或者驼峰式与下划线式对应),如果使用JdbcTemplate则可以使用这个RowMapper作为PO和数据库的映射 Spring 2.5 提供了一个便利的RowMapper实现-----BeanPropertyRowMapper 它可自动将一行数据映射到指定类的实例中 它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去。 BeanPropertyRowMapper是根据字段名和实体类中的标准Setter方法进行映射滴。也就是说,我们需要使表中的字段名和实体类的成员变量名称一致。
jdbc进行批量操作
@Override
public void batchAddBook(List<Object[]> batchArgs) {
String sql="insert into t_book values(?,?,?)";
int[] ints = jdbcTemplate.batchUpdate(sql, batchArgs);
System.out.println(Arrays.toString(ints));
}
5.事务管理
事务概念
1.什么是事务
事务是数据库操作最基本单元,逻辑上一组操作,要么都成功,如果有一个失败所有操作都失败,典型场景:银行转账
2.事务的四个特性(ACID)
1.原子性
2.一致性
3.隔离性
4.持久性
搭建事务操作环境
参考之前写的dao层,service层代码,注意注解和代理类
具体操作
1.事务添加到JavaEE三层结构里面的Service层
2.有两种方式:编程式事务管理和声明式事务管理
3.声明式事务管理
1.基于注解方式
2.基于xml配置文件方式
4.Spring进行声明式事务管理,底层使用AOP原理
5.Spring事务管理API
提供一个接口,代表事务管理器,这个接口针对不同框架提供不同实现类
事务操作(注解)
1.在spring配置文件配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean>
2.引入名称空间tx,开启注解
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
3.在service类上添加注解 @Transactional
如果检测到了异常,事件会还原到原来的状态
事务传播行为(propagation):
什么叫事务传播行为?听起来挺高端的,其实很简单。 即然是传播,那么至少有两个东西,才可以发生传播。单体不存在传播这个行为。
事务传播行为(propagation behavior)指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行。 例如:methodA事务方法调用methodB事务方法时,methodB是继续在调用者methodA的事务中运行呢,还是为自己开启一个新事务运行,这就是由methodB的事务传播行为决定的
事务方法:对数据库数据进行变化的操作
事务隔离级别(isolation)
1.事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题。
2.三个读问题:脏读,不可重复读,虚(幻)读
主要关注脏读
脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
事务操作(XML声明式)
<!--1.配置事务管理器--> <bean id="transactionManager" 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"/> </tx:attributes> </tx:advice> <!--3.配置切入点和切面--> <aop:config> <aop:pointcut id="pt" expression="execution(* org.example.service.UserService.*(..))"/> <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/> </aop:config>
事务操作(完全注解开发)
用配置类代替xml配置文件
@Configuration
@ComponentScan(basePackages = "org.example")
@EnableTransactionManagement
public class TxConfig {
//创建数据库连接池
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://localhost:3306/userdb");
druidDataSource.setUsername("root");
druidDataSource.setPassword("admin");
return druidDataSource;
}
@Bean
//创建jdbc模板对象,注意这里用datasource作为参数,意思是通过类型自动注入属性,因为ioc容器中已经有了datasource的实例
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
@Bean
//创建事务管理器
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager=new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}