Spring笔记
Spring笔记
1. Spring IOC
1.1 Spring核心包
XML编写提示:配置Schema,修改Key type 为Schema location
1.2. SpringIOC入门
IOC: Inversion of Control(控制反转)。将对象的创建权反转给(交给)Spring。
<bean id="bean1" class="com.joey.spring.Bean1"></bean>
DI:依赖注入,前提必须有IOC的环境,Spring管理这个类的时候将类的依赖的属性注入(设置)进来。
1.3. Spring工厂类结构图
ApplicationContext继承BeanFactory
BeanFactory
老版本的工厂类,在调用getBean的时候才会产生类的实例
ApplicationContext
新版本的工厂类,加载配置文件的时候,将Spring管理的类都实例化
两个实现类:
- ClassPathXmlApplicationContext:加载类路径下的配置文件
- FileSystemXmlApplicationContext:加载文件系统下的配置文件
1.4. Spring Bean配置
标签的id和name配置 id:使用了约束中的唯一约束,里面不能出现特殊字符。
name:没有使用约束中的唯一约束(理论上可以出现重复的,但是实际开发不能出现),里面可以出现特殊字符。
Bean的生命周期配置
init-method:Bean被初始化的时候执行的方法
destory-method:Bean被销毁的时候执行的方法(Bean是单例创建,工厂关闭)
Bean的作用范围配置
scope:Bean的作用范围
- singleton:默认单例模式创建对象
- prototype:多例模式
- request:应用在web项目中,Spring创建这个类以后存到request范围中
- session:应用在web项目中,Spring创建这个类以后存到session范围中
- globalsession:应用在web项目中,必须在porlet环境下使用,但是如果没有这种环境,相对于session
1.5. Spring的Bean管理(XML方式)
Spring的Bean的实例化方式
无参构造方法
编写类构造方法
public class Bean1{
public Bean1(){
super();
System.out.pringt("Bean1的无参构造方法执行。。。");
}
}编写XML配置文件
<bean id="bean1" class="com.joey.spring.Bean1"></bean>
静态工厂实例化
编写静态工厂
public class Bean2Factory{
public static Bean2 createBean2(){
System.out.pringt("Bean2的静态工厂方法执行。。。");
return new Bean2();
}
}编写XML配置文件
<bean id="bean2" class="com.joey.spring.Bean2Factory" factory-method="createBean2"></bean>
实例工厂实例化
编写实例工厂
public class Bean3Factory{
public static Bean3 createBean3(){
System.out.pringt("Bean3的实例工厂方法执行。。。");
return new Bean3();
}
}配置XML文件
<bean id="bean3Factory" class="com.joey.spring.Bean3Factory" ></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"></bean>
Spring的属性注入(DI)
构造方法的方式属性注入
<!-- 配置一个可以执行批量的sqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>Set方法的方式属性注入
<!--================== 配置和MyBatis的整合=============== -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis全局配置文件的位置 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="pooledDataSource"></property>
<!-- 指定mybatis,mapper文件的位置 -->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>P名称空间属性注入
引入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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">P名称空间的属性注入
<bean id="car" class="com.joey.spring.Car" p:name="" p:price=""></bean>
<bean id="employee" class="com.joey.spring.Employee" p:name="" p:car-ref="car"></bean>
SpEL的属性注入(Spring3.0以后)
spring表达式语言简称SPEL:是一个支持运行时查询和操作对象图的强大的表达式语言。语法类似于EL,SpEL 使用 #{…} 作为定界符 , 所有在大括号中的字符都将被认为是 SpEL , SpEL 为 bean 的属性进行动态赋值提供了便利。
通过 SpEL 可以实现:
- 通过 bean 的 id 对 bean 进行引用。
- 调用方式以及引用对象中的属性。
- 计算表达式的值
- 正则表达式的匹配
<bean id="carInfo" class="com.joey.spring.CarInfo"></bean>
<bean id="car" class="com.joey.spring.car">
<property name="name" value="#{carInfo.name}"></property>
<property name="drive" value="#{carInfo.drive()}"></property>
</bean>
Spring集合类型属性注入
<!-- Spring的集合属性的注入============================ -->
<!-- 注入数组类型 -->
<bean id="collectionBean" class="com.joey.spring.CollectionBean">
<!-- 数组类型 -->
<property name="arrs">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<!-- 注入list集合 -->
<property name="list">
<list>
<value>5</value>
<value>6</value>
<value>7</value>
</list>
</property>
<!-- 注入set集合 -->
<property name="set">
<set>
<value>aaa</value>
<value>bbb</value>
<value>ccc</value>
</set>
</property>
<!-- 注入Map集合 -->
<property name="map">
<map>
<entry key="aaa" value="111"/>
<entry key="bbb" value="222"/>
<entry key="ccc" value="333"/>
</map>
</property>
</bean>分模块开发配置
加载配置文件的时候加载多个
ApplicationCOntext applicationCOntext = new ClassPathXmlApplicationContext("applicationConetxt.xml","applicationConetxt.xml2");
在一个配置文件中引入多个配置文件
<import resource="applicationConetxt2.xml"/>
1.6. Spring的Bean管理(注解开发)
引入context约束
开启Spring组件扫描
<context:component-scan base-package="com.joey.spring"></context:component-scan>
类上添加注解
//相当于<bean id="userDao" class="com.joey.spring.UserDaoImpl"></bean>
public class UserDaoImpl implements UserDao{
}注解方式设置属性值
使用注解方式,可以没有set方法的
属性如果有set方法,需要将属性注入的注解添加到set方法
如果没有set方法,需要将属性注入的注解添加属性上
IOC 注解
- @Component:组件,修饰一个类,将这个类交给Spring管理
- 三个衍生注解,修饰类
- @Controller:Web层
- @ServIce:service层
- @Respository:dao层
- 属性注入的注解:
- 普通属性:@Value
- 按照类型对象注入:@Autoware
- 按照名称对象注入:@Resource
- Bean的其他注解:
- 生命周期相关注解
- PostConstruct:初始化方法
- PreDestory:销毁方法
- Bean作用范围的注解
- @Scope
- Singleton
- prototype
- request
- session
- globalsession
- @Scope
- 生命周期相关注解
IOC的XML和注解开发比较
XML :可以适用任何场景,结构清晰,维护方便
注解:有些地方用不了,类不是自己提供,开发方便
XML和注解整合开发:XML管理Bean,注解完成属性注入
没有使用扫描类上的注解,需要开启属性注入的注解
<context:annotation-config/>
基于XML配置 基于注解配置 Bean定义 @Component,衍生类:@Repository、@Service、@Controller Bean名称 通过id或name指定 @Component(“person”) Bean注入 或者通过p命名空间 @Autowired按照类型注入,@Qualifier按照名称注入 生命过程,Bean作用范围 init-method,destory-method,范围scope属性 @PostConstructa初始化、@PreDestory销毁、@Scope设置作用范围 适合场景 Bean来自第三方,使用其它 Bean的实现类由用户自己开发
2. Spring AOP
2.1 Spring 底层实现原理
动态代理
JDK动态代理(默认,先修改java文件然后再编译成class文件)
JDK动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承)
JDK动态代理主要涉及java.lang.reflect包下的两个类:Proxy类和InvocationHandler接口。
JDK动态代理实现的三个要点:
- 通过java.lang.reflect.Proxy类来动态生成代理类
- 代理类要实现InvocationHandler接口
- JDK动态代理只能基于接口进行动态代理的
Cglib动态代理(运行更快,在内存直接生成子类class文件继承父类重写所有父类方法(不能声明成final))
Cglib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有的父类方法的调用,并顺势织入横切逻辑。
区别
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而Cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
如果目标对象实现了接口,可以强制使用CGLIB实现AOP’
如何强制使用Cglib:
- 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>
- EnableAspectJAutoProxy注解参数proxyTargetClass=true使用Cglib
如果目标对象没有实现了接口,必须采用Cglib库,spring会自动在JDK动态代理和Cglib之间转换
JDK动态代理和Cglib字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。 因为是继承,所以该类或方法最好不要声明成final性能问题
由于Cglib代理是利用ASM字节码生成框架在内存中生成一个需要被代理类的子类完成代理,而JDK动态代理是利用反射原理完成动态代理,所以Cglib创建的动态代理对象性能比JDK动态代理动态创建出来的代理对象新能要好的多,但是对象创建的速度比JDK动态代理要慢,所以,当Spring使用的是单例情况下可以选用Cglib代理,反之使用JDK动态代理更加合适。同时还有一个问题,被final修饰的类只能使用JDK动态代理,因为被final修饰的类不能被继承,而Cglib则是利用的继承原理实现代理的。
2.2 Spring AOP相关术语
Joinpoint(连接点) :
所谓连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点。
Pointcut(切入点) :
所谓的切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强) :
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置类型,后置通知,异常通知,环绕通知。
Introduction(引介) :
引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。
Target(目标对象) :
代理的目标对象。
Weaving(织入) :
是指把增强应用到目标对象来创建新的代理对象的过程。
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
Proxy(代理) :
一个类被AOP织入增强,就产生一个结果代理类。
Aspect(切面) :
是切入点和通知(引介)的结合。
2.3 SpringAOP 的入门开发
引入jar包
编写目标类并配置
编写切面类并配置
进行aop配置
<aop:config>
<aop:pointcut expression="execution(表达式" id="pc1"/>
<aop:aspect >
<aop:before method="" pointcut-ref="pc1"/>
</aop:aspect>
</aop:config>通知类型
- 前置通知
- 后置通知
- 环绕通知
- 异常抛出通知
- 最终通知
XML配置
基于execution的函数完成
[访问修饰符] 方法返回值 包名.类名.方法名(参数)
2.4 基于AspectJ的XML配置
<aop:aspect > |
2.5 基于AspectJ的注解配置
在配置文件中开启AOP注解开发
<aop:aspectj-autoproxy/>
切面类上使用注解
public class MyAspectj{
public void before(){
System.out.println("前置通知");
}
public void afterReturning(){
System.out.println("后置通知");
}
public void around(){
System.out.println("环绕通知");
}
public void afterThrowing(){
System.out.println("异常抛出通知");
}
public void after(){
System.out.println("最终通知");
}
}
3. Spring的JDBC模板使用
Spring的JDBC模板
ORM持久化技术 模板类 JDBC org.springframework.jdbc.core.JdbcTemplate Hibernate3.0 org.springframework.orm.hibernate3.HeibernateTemplate IBatis(Mybatis) org.springframework.orm.ibatis.SqlMapClientTemplate JPA org.springframework.orm.jpa.JpaTemplate JDBC模板使用(例: c3p0)
引入jar包
配置c3p0连接池
抽取配置到属性文件
在Spring的配置文件中引入属性文件
<!--第一种(常用)-->
<context:property-placeholder location="classpath:dbconfig.properties" />
<!--第二种-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:dbconfig.properties"/>
</bean>引入属性文件的值
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
4. Spring 的事务管理
4. 1 事务特性
- 原子性 : 事务不可分割
- 一致性 : 事务执行前后数据完整性保持一致
- 隔离性 : 一个事务的执行不应该受到其他事务的干扰
- 持久性 : 一旦事务结束,数据就持久到数据库
4.2 事务隔离级别
Read uncommitted :未提交读,任何读问题解决不了。
Read committed :已提交读,解决脏读,但是不可重复读和虚读有可能发生。
Repeatable read :重复读,解决脏读和不可重复读,但是虚读有可能发生。
Serializable :解决所有读问题。
4.3 事务管理的API
PlatformTransactionManager: 平台事务管理器
- DataSourceTransactionManager: 底层使用JDBC管理事务
- HibernateTransactionManager : 底层使用Hibernate管理事务
事务定义信息
用于定义事务的相关信息
- 隔离级别
- 超时信息
- 传播行为
- 是否只读
事务的状态
用于记录在事务管理过程中, 事务的状态的对象
4.4 Spring事务的传播行为(七种事务)
- 保证多个操作在同一个事务中
- PROPAGATION_REQUIRED :默认值,如果A中有事务,使用A中的事务,如果A没有,创建一个新的事务,将操作包含进来
- PROPAGATION_SUPPORTS :支持事务,如果A中有事务,使用A中的事务。如果A没有事务,不使用事务。
- PROPAGATION_MANDATORY:如果A中有事务,使用A中的事务。如果A没有事务,抛出异常。
- 保证多个操作不在同一个事务中
- PROPAGATION_REQUIRES_NEW :如果A中有事务,将A的事务挂起(暂停),创建新事务,只包含自身操作。如果A中没有事务,创建一个新事务,包含自身操作。
- PROPAGATION_NOT_SUPPORTED :如果A中有事务,将A的事务挂起。不使用事务管理。
- PROPAGATION_NEVER:如果A中有事务,报异常。
- 嵌套式事务
- PROPAGATION_NESTED:嵌套事务,如果A中有事务,按照A的事务执行,执行完成后,设置一个保存点,执行B中的操作,如果没有异常,执行通过,如果有异常,可以选择回滚到最初始位置,也可以回滚到保存点。
4.5 Spring事务管理
编程式事务(需手动编写代码)
- 配置平台事务管理器
- 配置事务管理的模板类
- 在业务层注入事务管理的模板
- 编写事务管理的代码
声明式事务管理(XML方式)
配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--控制住数据源 -->
<property name="dataSource" ref="pooledDataSource"></property>
</bean>配置增强
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有方法都是事务方法 -->
<tx:method name="*"/>
<!--以get开始的所有方法 -->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>AOP配置
<aop:config>
<!-- 切入点表达式 -->
<aop:pointcut expression="execution(* com.joey.service..*(..))" id="txPoint"/>
<!-- 配置事务增强 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
声明式事务管理(注解方式)
配置事务管理器
<!--配置事务增强,事务如何切入 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 所有方法都是事务方法 -->
<tx:method name="*"/>
<!--以get开始的所有方法 -->
<tx:method name="get*" read-only="true"/>
</tx:attributes>
</tx:advice>开启注解事务
<tx:annotation-driven transaction-manager="transationManager"/>
在业务层添加注解
public class UserServiceImple implements UserService{
}