Spring的核心功能
IOC:
方便解耦, 简化开发
IOC不是一种技术而是一种设计思想
AOP:
面向切面编程
Spring提供面向切面编程, 可以方便的实现对程序进行权限拦截、运行监控等功能
声明式事务的支持:
通过配置完成对事务的管理, 无需手动编程
方便的测试功能:
Spirng-test模块可以继承Junit依赖, 通过注解进行测试
框架整合:
Spring框架可以无缝整合其他框架
Spring的核心模块
spring-core: 依赖注入IoC与DI的最基本实现
spring-beans: Bean工厂与bean的装配
spring-context: spring的context上下文即IoC容器
spring-context-support
spring-expression: spring表达式语言
什么是IOC
IOC - Inversion of Control 控制反转思想
传统的创建对象方法是通过new 关键字, 而spring则是通过IoC容器来创建对象
也就是说我们将对象的创建、初始化、销毁等工作交给了IoC容器! 以达到程序的高度解耦的目的!
Spring容器可以说是一个IoC容器(装对象, 对象的容器!)
DI - 依赖注入
DI - Dependency Injection
在创建对象实例时, 同时为这个对象注入它所依赖的属性
相当于把bean与bean之间的关系交给容器处理, 而这个容器就是spring
applicationContext.xml配置文件详解
根标签:
beans
子标签:
bean
如果要注入对象依赖, 则是根标签内必须包含的标签, 用于声明具体的类的对象
bean标签对应属性:
class --> 指定bean对应类的全路径
name --> name是bean对应对象的一个标识
scope --> bean对象创建模式和生命周期
id --> bean对象唯一标识, 不能添加特别字符!
lazy-init --> 是否延时加载, 默认值为false
init-method --> 对象初始化方法
destroy --> 对象销毁方法
Scope属性:
singleton - 默认值, 容器创建的对象是单例
prototype - 创建的对象是多例(每次使用都创建新对象)
request - 一次请求范围内, 容器中的对象保持同一个
session - 一次会话范围内, 容器中的对象保持同一个
global session - 类似HTTP session的作用域, 但是仅仅在基于protlet的web应用中才有意义
lazy-init属性在使用时需注意, 只有在单例模式下才有意义
Spring框架创建对象方式
1. 调用的默认的无参数的构造方法创建对象
<bean id = "s1" class = "com.spring.bean.Student">
<property name = "id" value = "9527"/>
<property name = "name" value = "小张"/>
<property name = "money" value = "123.45"/>
<property name = "age" value = "18"/>
</ bean>
2. 调用有参数构造方法创建对象
<bean id = "s2" class = "com.spring.bean.Student">
<constructor-arg name = "name" value = "周星星" index = "1" type = "java.lang.String"/>
<constructor-arg name = "id" value = "1110" index = "0" type = "java.lang.Integer"/>
<constructor-arg name = "age" value = "45" index = "2" type = "java.lang.Integer"/>
<constructor-arg name = "money" value = "456.78" index = "3" type = "java.lang.Double"/>
</ bean>
3. 调用静态工厂创建对象
<bean id = "s3" class = "com.spring.bean.Student" factory-method = "createStudent"/>
4. 调用非静态工厂创建对象
<bean id = "factory1" class = "com.spring.bean.StudentFactory1"/>
<bean id = "s4" factory-bean="factory1" factory-method="createStudent"/>
依赖注入
1. Set方法注入
1.1 基本类型注入
<bean name = "person" class = "com.itqf.spring.bean.Person">
<property name = "name" value = "jeck"/>
<property name = "age" value = "11"/>
</ bean>
1.2 引入类型注入
<bean name = "person" class = "com.itqf.spring.bean.Person">
<property name = "name" value = "helen"/>
<property name = "age" value = "18"/>
<property name = "car" ref = "car"/>
</ bean>
<bean name = "car" class = "com.itqf.spring.bean.Car">
<property name = "name" value = "MINI"/>
<property name = "color" value = "grey"/>
</ bean>
2. 构造方法注入
2.1 单个有参数构造方法注入
<bean name = "person" class = "com.itqf.spring.bean.Person">
<constructor-arg name = "name" value = "rose"/>
<constructor-arg name = "age" value = "18"/>
< bean/>
2.2 多个构造方法但参数种类顺序不同时用Index定位
<bean name = "person" class = "com.itqf.spring.bean.Person">
<constructor-arg name = "name" value = "helen" index = "0"/>
<constructor-arg name = "age" value = "18" index = "1"/>
</ bean>
2.3 多个构造方法参数名和位置一致但种类不同时用type定位
<bean name = "person" class = "com.itqf.spring.bean.Person">
<constructor-arg name = "name" value = "9527" type = "java.lang.Integer"/>
<constructor-arg name = "age" value = "18" type = "java.lang.Integer"/>
</ bean>
3. P名称空间注入
此方法需要修改xml文件表头
xmlsn:p="http://www.springframework.org/schema/p"
<bean name = "person1" class = "com.iqtf.srping.bean.Person" p:name = "jack" p:age = "18"/>
4. spel注入
<bean name = "person" class = "com.iqtf.srping.bean.Person" p:name = "#{person1.name}" p:age = "#{person1.age}"/> (调用了上方的数据)
注解
Spring注解开发:注解简化开发!
@Component:给类生成对象,类注解,对象名默认是类名(首字母小写),也可以自己定义名字!例如:@Component("p1")
@Value:给属性赋值 属性或者set方法注解 @Value("${p.pass}") 引用外部的属性文件
@AutoWired:根据类型自动装配对象。如果匹配到多个对象,直接异常!
@Autowired //根据类型自动装配, 万一Spring框架中有多个对象可以匹配?
@Qualifier("a1") //指定使用容器中的哪一个对象!
@Resource:如果没有配置名字,那么就根据类型匹配,如果匹配到多个类型,那么异常。如果指定了名字,那么根据名字匹配!
@Resource("name") == @Autowired + @Qualifier("name")
@Resource(name = "${dog.type}")
@PostConstruct和 @PreDestroy 注解,对象初始化和销毁的注解方法
@Scope("prototype") 设置类单例还是多例
@Scope("singleton") 默认单例
@Repository Dao层 数据库访问层创建对象注解
@Service Service层 业务逻辑层创建对象注解
@Controller Servlet层 表述层创建对象注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml") JUnit和test核心组合使用注解!
AOP静态/动态代理
AOP - Aspect Oriented Programming 面向切面编程
OOP - Object Oriented Programming 面向对象编程
个人对AOP理解:
在不修改源代码的情况下, 对源代码进行功能的添加, 例如日志功能、事务功能. . . .
案例需求:
有一个User类下存在添加用户和删除用户两个方法, 需要对两个方法添加开启事务和提交事务的功能.
1. 静态代理:
创建一个代理类, 继承Service接口( 继承与核心源代码相同的接口) , 在代理类中重写添加和删除方法, 在其中添加开启和提交事务的功能
2. JDK动态代理:
通过继承InvocationHandler接口来完成JDK动态代理
public class ObjectInterceptor implements InvocationHandler {
private Object target;
private Mytransaction transaction;
public ObjectInterceptor ( Object target, Mytransaction transaction) {
this . target = target;
this . transaction = transaction;
}
public Object invoke ( Object proxy, Method method, Object[ ] args) throws Throwable {
this . transaction. before ( ) ;
method. invoke ( this . target, args) ;
this . transaction. after ( ) ;
return null;
}
}
public class Test {
@Test
pubic void test ( ) ) {
Object target = new UserServiceImpl ( ) ;
ObjectInterceptor proxy = new ObjectINterceptor ( target, new Mytransaction ( ) ) ;
UserService userService = ( UserService) Proxy. newProxyInstance ( target. getClass ( ) . getClassLoader ( ) , target. getClass ( ) . getInterfaces ( ) , proxy) ;
userService. addUser ( new User ( . . . . ) ) ;
userService. deleteUser ( 1 ) ;
}
}
通过反编译Spring框架自动生成的接口实现类的. java文件可以发现, 底层代码其实是调用了父类的invoke方法.
可以从JDK代理的核心方法invoke看出他只能为接口创建代理实例, 而当我们需要创建的代理实例是一个类时, 我们就需要使用CGLib代理替代他.
3. CGLib代理 - 字节码技术, 可以为类创建子类, 在子类中拦截所有父类的方法并植入逻辑
需要导入依赖
< dependency>
< groupId> cglib< / groupId>
< artifactId> cglib< / artifactId>
< version> 2.2 < / version>
< / dependency>
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer ( ) ;
private MyTransaction transaction;
public CGLibProxy ( MyTransaction transaction) {
this . trsansaction = transaction;
}
public Object getProxy ( Class clazz ) {
enhancer. setSuperclass ( clazz) ;
enhancer. setCallback ( this ) ;
return enhancer. create ( ) ;
}
public Object intercept ( Object obj, Method method, Object[ ] ojbs, MethodProxy methodProxy) throws Throwable {
transaction. before ( ) ;
Object invoke = methodProxy. invokeSuper ( obj, ojbs) ;
transaction. after ( ) ;
return invoke;
}
}
@Test
public void test ( ) {
CGLibProxy proxy = new CGLibProxy ( new MyTransaction ( ) ) ;
UserServiceImpl userService = ( UserServiceImpl) proxy. getProxy ( UserServiceImpl. class ) ;
userService. addUser ( new User ( . . . ) ) ;
userService. deleteUser ( 1 ) ;
}
JDK和CGLib动态代理的区别:
1. JDK动态代理生成的代理类和委托类实现了相同的接口
2. CGLib动态代理中生成的代理类是委托类的子类, 且不能处理被Final修饰的方法
3. JDK采用反射机制调用委托类的方法, CGLib采用类似索引的方式直接调用委托类方法
AOP注解编程 *
术语:
1. target: 目标类, 需要被代理的类
2. joinpoint: 连接点, 指可能被拦截到的方法
3. pointCut: 切入点, 已经被增强的连接点
4. advice: 通知/增强, 增强代码
5. weaving: 织入, 指把advice应用到目标对象target来创建新的代理对象proxy的过程
6. proxy: 代理类, 通知 + 切入形成的子类或实体类
7. aspect: 切面, advice和pointcut的结合
增强类环绕通知参数:ProceedingJoinPoint
Xml配置文件格式:
<?xml version="1.0" encoding="UTF-8"?>
< beans xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xmlns = " http://www.springframework.org/schema/beans" 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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd" >
< bean name = " userService" class = " com.bruceliu.service.UserServiceImpl" />
< bean name = " myAdvice" class = " com.bruceliu.dao.MyAdivce" />
< aop: config>
< aop: pointcut id = " pc" expression = " execution(* com.bruceliu.service.*ServiceImpl.*(..))" />
< aop: aspect ref = " myAdvice" >
< aop: before method = " before" pointcut-ref = " pc" />
< aop: after-returning method = " afterReturning" pointcut-ref = " pc" />
< aop: around method = " around" pointcut-ref = " pc" />
< aop: after-throwing method = " afterException" pointcut-ref = " pc" />
< aop: after method = " after" pointcut-ref = " pc" />
</ aop: aspect>
</ aop: config>
</ beans>
注解格式:
< aop: aspectj-autoproxy> </ aop: aspectj-autoproxy>
< context: component-scan base-package = " com.aop.*" >
package com. aop. advice;
import org. aspectj. lang. ProceedingJoinPoint;
import org. aspectj. lang. annotation. *;
import org. springframework. stereotype. Component;
@Aspect
@Component
public class MyAdvice {
@Pointcut ( "execution(* com.aop.service.impl.*.*(..))" )
public void pc ( ) { }
@Around ( "MyAdvice.pc()" )
public Object aroundMethod ( ProceedingJoinPoint pjp) {
Object o = null;
try {
System. out. println ( "前置通知" ) ;
o = pjp. proceed ( ) ;
System. out. println ( "后置通知" ) ;
} catch ( Throwable throwable) {
System. out. println ( "出现异常, 信息为:" + throwable. getMessage ( ) ) ;
} finally {
System. out. println ( "最终通知" ) ;
}
return o;
}
}
Spring整合Mybatis
依赖导入:
< dependency>
< groupId> com.alibaba</ groupId>
< artifactId> druid</ artifactId>
< version> ${druid.version}</ version>
</ dependency>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis-spring</ artifactId>
< version> ${mybatis.spring.version}</ version>
</ dependency>
< resources>
< resource>
< directory> src/main/java</ directory>
< includes>
< include> **/*.xml</ include>
</ includes>
</ resource>
</ resources>
JDBC.properties:
jdbc.Driver=com.mysql.jdbc.Driver
jdbc.Url=jdbc:mysql://127.0.0.1:3306/ssm20190917?characterEncoding=utf-8
jdbc.username=root
jdbc.Password=123456
applicationContext.xml配置:
< context: component-scan base-package = " com.sm.*" >
< context: property-placeholder location = " classpath:jdbc.properties" >
< bean id = " ds" calss = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " ${jdbc.Driver}" />
< property name = " url" value = " ${jdbc.Url}" />
< property name = " username" value = " ${jdbc.username}" />
< property name = " password" value = " ${jdbc.Password}" />
</ bean>
< bean id = " factory" class = " org.mybatis.spring.SqlSessionFactoryBean" >
< property name = " dataSource" ref = " ds" />
< property name = " configLocation" value = " classpath:mybatis-config.xml" />
< property name = " mapperLocations" value = " classpath:com/sm/mapper/*.xml" />
< property name = " typeAliasesPackage" value = " com.sm.bean" />
</ bean>
< bean>
<property name="org.mybatis.spring.mapper.MapperScannerConfigurer" value = "com.sm.mapper"/>
</ bean>
< bean id = " transactionManager" class = " org.springframework.jdbc.datasource.DataSourceTransactionManager" >
< property name = " dataSource" ref = " ds" />
</ bean>
< tx: annotation-driven transaction-manager = " transactionManager" />
默认情况下< tx: annotaion-driven/> 中transaction-manager属性会自动使用名为"transactionManager"的事务管理器
所以, 如果用户将事务管理器(第六步)中的id定义为"transactionManager"可以将其简化为< tx: annotaion-driven/>
Spring事务基本属性
@Transactional注解后方()中可以配置
只读:read-only(默认值为false)
设置事务是否对后端的数据库进行修改操作
可以在查询方法中设置只读属性为true以提高性能
事务超时:time-out(时间单位为秒 默认值为-1)
当事务运行太长的时间, 自动回滚, 而不是一直等待其结束
回滚规则: 默认遇到运行时异常事务回滚
no-rollback-for()
rollback-for()
隔离级别: 四大隔离级别
默认的隔离级别和数据库相同, 例如Mysql默认的隔离级别是repeatable-read
而Oracle的默认隔离级别是Read-Commited
传播行为: 七大传播行为
Propagation_REQUIRED:
默认值, 如果当前没有事务, 就新建一个事务
如果已经存在一个事务中就加入到这个事务中
Propagation_SUPPORTS:
支持当前事务, 如果当前没有事务, 就以非事务方式执行
Propagation_MADATORY:
使用当前事务, 如果没有事务就抛出异常
Propagation_REQUIRES_NEW:
新建事务, 如果当前存在事务就把当前事务挂起
Propagation_NOT_SUPPORTED:
以非事务方式执行操作, 如果当前存在事务就把当前事务挂起
Propagation_NEVER:
以非事务方式执行操作, 如果当前存在事务则抛出异常
Propagation_NESTED:
如果当前存在事务, 则在嵌套事务内执行
如果当前没有事务则执行与REQUIRED类似的操作