Spring
1. Spring的基本概述
-
spring是一个轻量级的JAVAEE的开源框架
-
spring可以解决企业级应用开发的复杂性
-
spring有两个核心部分IOC和AOP:
IOC:控制反转,把创建对象的过程交给spring进行管理
AOP:面向切面,在不修改源代码的情况下进行功能的增强
-
spring的特点:
方便解藕,简化开发
Aop编程的支持
方便测试的集成
方便和其他的框架进行整合
方便进行事务的操作和降低api的使用难度
2. IOC容器
2.1 什么是IOC?
-
控制反转,把对象创建和对象之间的调用过程,全部交给spring来进行管理
-
使用IOC的目的就是为了降低耦合度
-
IOC思想基于IOC容器完成,底层就是对象工厂
-
Spring提供IOC容器实现的两种实现方式:
BeanFactory:
IOC容器的基本实现,是spring内部的使用接口,不提供开发人员进行使用,加载配置文件的时候不会进行对象的创建,在使用的时候才会进行对象的创建
ApplicationContext:
BeanFactory的子接口,提供了更加强大的功能,一般由开发人员进行使用,加载配置文件的时候,对象就会进行创建
ApplicationContex有实现类:
FileSystemXmlApplicationContext: 当前类在系统盘的路径地址
ClassPathXmlApplicationContext: 当前类在src下的路径地址
2.2 IOC的底层实现原理
xml解析/工厂模式/反射
第一步xml配置文件,配置创建的对象,第二步创建工厂类根据反射创建对象
2.3 Bean的两种类型
-
普通bean:在配置文件中定义的是什么类型就返回什么类型
-
工厂bean:在配置文件中定义的类型可以和返回类型不一致,实现FactoryBean,重写getObject方法
2.4 Bean的作用域
spring创建的bean分为单实例和多实例
spring默认创建的bean是单实例的
设置单实例还是多实例的方式:
设置bean标签scope,单实例scope=“singleton”,多实例scope=“prototype”,加载配置文件的时候并会创建bean
设置了多实例scope=“prototype”之后。加载配置文件的时候并不会创建bean,会在getBean的时候进行对象的创建
2.5 Bean的生命周期
<!--定义:一个对象从创建到销毁的过程-->
-
通过构造去创建bean的实例,(无参构造)
-
为bean的数据设置值和其他bean引用(调用set方法)
-
(初始化之前调用前置处理器 )-实现BeanPostProcessor
-
调用bean的初始化方法(需要进行配置)
-
(初始化之后调用后置处理器)-实现BeanPostProcessor
-
bean可以使用了(对象获取到了)
-
当容器关闭的时候调用bean的销毁方法(需要进行配置)
2.6 IOC操作Bean的管理
什么是自动装配?
spring根据指定的装配规则(属性名称或者属性类型),将属性值注入
xml的自动装配:在bean标签增加autowire属性:byName:根据名称进行注入,byType:根据type进行注入
注意:根据类型匹配时候,如果有相同类型的两个bean就会报错,不知道选择哪个bean进行注入
2.7 IOC操作Bean基于注解方式
什么是注解?
注解是一种特殊的代码标记,用来作用到类,方法,属性上面,格式:@注解名称(属性名称=属性值,...),使用的目的就是可以简化开发
spring针对Bean的管理中创建对象提供的注解:
@Component:一种普通的注解通过他都可以创建对象,相当于xml中的 bean标签
@Service:一般用在业务逻辑层
@Controller:一般用在web层
@Repository:一般用在dao层
注意:上面的四个注解功能一样,都可以创建bean的实例
spring注解方式实现属性的注入
@AutoWired:根据属性类型进行注入
@Qualifier:根据属性名称进行注入(和@AutoWired组合使用)
@Resource:可以根据属性类型进行注入,也根据属性名称进行注入
@Value:注入普通类型属性
完全注解开发
(1)创建配置类,替代xml
@Configuration(作为配置类)
@ComponentScan(basePackages=“扫描的包地址”)
@Configuration
@ComponentScan(basePackages = {"com.wrh.spring"})
public class SpringConfig {
}
通过new AnnotationConfigApplicationContext(“类名”)加载
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
3. AOP
什么是aop?
aop就是面向切面的编程,利用AOP可以对业务逻辑的各个部分进行隔离,这样可以使业务逻辑之间的耦合度降低,提高程序的重用性,同时提高了开发效率,可以在不修改源代码的基础上进行功能的增强
底层原理:aop使用动态代理的方式实现
3.1代理的两种方式:
(1)有接口的情况下:使用jdk的动态代理
<!--创建接口实现类的代理对象,在代理对象的基础上进行增强-->
(2)无接口的情况下:CGLIB动态代理
<!--创建对象的子类的代理对象,在代理对象的基础上进行增强-->
aop-jdk的动态代理:
(1)调用newProxyIntance
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader loader:类加载器
Class<?>[] interfaces:增强方法所在的类,这个类实现的接口,支持多个接口
InvocationHandler h:实现InvocationHandler的对象,创建代理对象,写增强方法
(2)jdk代理代码实现:
/**
* @author wangruiheng
*/
public class JdkProxy {
public static void main(String[] args) {
//接口对象
Class<?>[] interfaces = {UserDao.class};
//接口实现的方法-需要增强的类
UserDaoImpl userDaoImpl = new UserDaoImpl();
UserDao userDao = (UserDao)Proxy.newProxyInstance(JdkProxy.class.getClassLoader(),interfaces,new UserDaoInvocationHandler(userDaoImpl));
userDao.add(1, 2);
}
}
/**
* 创建代理对象
*/
class UserDaoInvocationHandler implements InvocationHandler {
private Object o;
//把创建是谁的代理对象把谁传递过来
public UserDaoInvocationHandler(Object o){
this.o=o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法之前执行"+method.getName() + Arrays.toString(args));
Object res = method.invoke(o, args);
System.out.println("方法之后执行");
return res;
}
3.2 aop的术语
连接点:类里面的那些方法可以被增强,这些方法就被称为连接点
切入点:实际真正被增强的方法就是切入点
通知(增强):实际增强逻辑的部分就叫做通知,(增加的部分逻辑)5种通知类型:
(1)前置通知
(2)后置通知
(3)环绕通知
(4)异常通知
(5)最终通知
切面:是一个动作(把一个通知应用到切入点的过程)
<!--spring一般都是基于AspectJ实现AOP操作-->
<!--AspectJ是一个独立的aop框架,不属于spring的组成部分,一般进行组合使用进行aop操作-->
3.3 aop的实现
切入点的表达式:execution(权限修饰符,返回值类型,类的全路径,方法名称,参数列表)
<!--例子:execution(* com.wrh.spring.*(..))-->
基于xml配置文件实现:
<!--配置bean-->
<bean id="user" class="com.wrh.spring.aopxml.User"></bean>
<bean id="userProxy" class="com.wrh.spring.aopxml.UserProxy"></bean>
<!--配置aop增强-->
<aop:config >
<!--配置切入点-->
<aop:pointcut id="p" expression="execution(* com.wrh.spring.aopxml.User.add(..))"/>
<!--配置切面-->
<aop:aspect ref="userProxy">
<aop:after method="before" pointcut-ref="p"></aop:after>
</aop:aspect>
</aop:config>
基于注解实现:
(1)创建一个类,被增强的类
/**
* @author wangruiheng
*/
@Component
public class Books {
public void add(){
System.out.println("add.................");
}
}
(2)创建一个类,编写增强的逻辑(五种通知类型)
/**
* @author wangruiheng
*/
@Component
@Aspect
public class BooksProxy {
@Pointcut("execution(* com.wrh.spring.aop.Books.add(..))")
public void pointcut(){}
/**
* 前置通知
*/
@Before("pointcut()")
public void before(){
System.out.println("前置通知");
}
/**
* 后置通知
*/
@After("pointcut()")
public void after(){
System.out.println("后置通知");
}
/**
* 后置通知,在将返回值返回时执行
*/
@AfterReturning("pointcut()")
public void afterReturning(){
System.out.println("后置通知,在将返回值返回时执行");
}
/**
* 异常通知
*/
@AfterThrowing("pointcut()")
public void afterThrowing(){
System.out.println("后置异常通知");
}
/**
* 环绕通知
*/
@Around("pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知---之前");
proceedingJoinPoint.proceed();
System.out.println("环绕通知---之后");
}
}
(3)进行通知的配置
在spring中开启注解扫描
<!--开启注解扫描 -->
<context:component-scan base-package="com.wrh.spring.aop"></context:component-scan>
使用注解创建 被增强的类和增强类@Component
在增强类上加一个注解@AspectJ
在spring配置文件中开启生成代理对象
<!--开启生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
(4) 相同切入点的提取
@Pointcut("execution(* com.wrh.spring.aop.Books.add(..))")
public void pointcut(){}
(5)多个切面时,可以通过@Order(参数【数值类型,数字越小优先级越高】)进行设置优先级
(6)全注解开发
/**
* @author wangruiheng
*/
@Configuration//这个类是配置类
@EnableAspectJAutoProxy(proxyTargetClass = true)//开启生成代理类
@ComponentScan(basePackages = {"com.wrh.spring"})//扫描注解
public class SpringConfig {
}
4. JdbcTemplate
什么是JdbcTemplate?
JdbcTemplate是spring对jdbc的封装,对数据库的操作更加方便
4.1JdbcTemplate的配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db" ></property>
<property name="username" value="root" ></property>
<property name="password" value="tiger" ></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver" ></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="com.wrh.spring"></context:component-scan>
@Test
public void add(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
UserServiceImpl userServiceImpl = applicationContext.getBean("userServiceImpl", UserServiceImpl.class);
User user = new User();
user.setId(2);
user.setName("小花");
user.setSex("女");
userServiceImpl.add(user);
}
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void add(User user) {
String sql = "insert into users VALUES(?,?,?);";
int update = jdbcTemplate.update(sql,user.getId(), user.getName(), user.getSex());
System.out.println(update);
}
5. 事务管理
什么是事务?
事务式数据库操作的基本单元。逻辑上的一组操作,要么都成功,要么都失败,典型的场景:银行转账
5.1 事务的四个特性:(ACID)
-
原子性:(过程中不可分割,要么都成功要么都失败)
-
一致性:(操作之前和操作之后总量不变)
-
隔离性:(多事务操作的时候彼此之前不产生影响)
-
持久性:(事务操作完成之后数据存入数据库)
5.2 事务操作
spring事务操作的步骤
1.事务添加到service层(业务逻辑层)
2.事务分为两种:编程式和声明式事务管理
3.声明式事务管理:
(1)基于注解方式
在spring配置文件中配置事务管理器
-
配置事务管理器
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="url" value="jdbc:mysql:///user_db?useSSL=false&useTimezone=true&serverTimezone=GMT%2B8" ></property> <property name="username" value="root" ></property> <property name="password" value="tiger" ></property> <property name="driverClassName" value="com.mysql.jdbc.Driver" ></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <context:component-scan base-package="com.wrh.spring"></context:component-scan> <!--配置事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置通知--> <tx:advice id="advice"> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--配置切入点和切面--> <aop:config> <!--配置切入点--> <aop:pointcut id="pt" expression="execution(* com.wrh.spring.service.UserServiceImpl.*(..))"/> <!--配置切面--> <aop:advisor advice-ref="advice" pointcut-ref="pt"></aop:advisor> </aop:config>
(2)基于xml配置文件方式
4.在spring中进行声明式事务管理,底层使用aop原理
5.3 spring事务管理api
(1)提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
PlatFormTransactionManager
(2)spring配置事务
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="url" value="jdbc:mysql:///user_db" ></property>
<property name="username" value="root" ></property>
<property name="password" value="tiger" ></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver" ></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<context:component-scan base-package="com.wrh.spring"></context:component-scan>
<!--配置事务管理器-->
<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>
添加注解@Transactional
5.4 注解的相关属性
propagation:事务的传播行为(<!--多事务之间的调用,事务之间是如何管理的-->)
<!--REQUIRED:如果有事务在运行,当前的方法就在这个事务内运行,否则就启动一个新的事务,并在自己的事务内运行-->
<!--REQUIRED_NEW:当前的方法必须启动新的事务,并在自己的事务内运行,如果有事务运行,应该将它挂起-->
<!--SUPPORTS:如果有事务运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中-->
<!--NOT_SUPPORTE:当前的方法是不运行在事务中,如果有运行的事务,就将它挂起-->
<!--MANDATORY:当前的方法必须运行在事务内部,如果没有正在运行的事务,就抛出异常-->
<!--NEVER:当前的方法不应该运行在事务中,如果有运行的事务就抛出异常-->
<!--NESTED:如果有事务运行,当前方法就应该在这个事务的嵌套事务内运行,否则,就启动一个新的事务,并在它自己的事务内运行-->
ioslation:事务的隔离级别(事务有特性称为隔离性,多事务操作之间不会产生影响,不考虑事务的隔离性会产生很多的问题)
脏读:一个未提交的事务读取到一个未提交的数据
不可重复读:一个未提交的事务读取到一个已提交事务修改的数据
幻读:一个未提交的事务读取到一个已提交事务添加的数据
timeout:超时时间(单位秒,默认-1,不超时)
readOnly:是否只读(默认是false。可以查询也可以修改,开启之后只内查询不能修改)
rollbackFor:回滚(出现哪些异常类型回滚)
norollbackFor:不回滚(出现哪些异常类型不进行回滚)
5.5 全注解开发
@Configuration //配置类
@ComponentScan //组建扫描
@EnableTransactionManagement //开启事务
@Bean //创建bean