Spring
spring的xml配置
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
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
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
</beans>
IOC
IoC Inversion of Control : 控制反转,是一个理论,一个指导思想。指导开发人员如何使用对象,管理对象的。把对象的创建,属性赋值,对象的生明周期都交给代码之外的容器管理。
控制和反转
-
控制:对象创建,属性赋值,对象声明周期管理
-
反转:把开发人员管理对象的权限转移给了代码之外的容器实现,有容器完成对象的创建。
-
正转:开发人员在代码中,使用new构造方法创建对象,开发人员掌握了对象的创建,属性赋值,对象从开始到销毁的全部过程。开发人员有对 对象 全部控制。
通过容器,可以使用容器中的对象吗(容器已经创建了对象,对象属性赋值了,对象也组装好了)
Spring就是一个容器,可以管理对象,创建对象,给属性赋值
IoC的技术实现
DI (依赖注入):Dependency Injection,缩写是DI,是IoC的一种技术实现,程序只需要提供要使用的对象的名称就可以,对象如何创建,如何从容器中查找,获取都由容器内部自己实现。
依赖名词:比如说ClassA类使用了ClassB的属性或方法,叫做ClassA依赖ClassB,
public class ClassB{
public void createOrder(){}
}
public class ClassA{
//属性
private ClassB b = new ClassB();
public vouid buy(){
b.createOrder();
}
}
执行ClassA的buy()
ClassA a = new ClassA();
a.buy();
Spring框架使用的DI实现IoC
通过spring框架,只需要提供使用的对象名词就可以,从容器中获取名称对应的对象。
spring底层使用的 反射机制, 通过反射创建对象,给属性。
spring包的含义
spring的核心包:spring-core
单元测试
//创建工厂对象
public void test(){
//读取项目内部的配置文件信息的工厂信息
ApplicationContext c = new ClassPathXmlApplicationContext("appcationContext");
UserDao ud=(UserDao) c.getBean("userDao");
ud.add();
}
DI
依赖注入,需要有IOC的环境配置
注入方式
- set
- 构造器
- 注解
构造器
需要有对应注入参数的有参构造函数
<bean id="user" class="cn.hp.entity.User">
<constructor-arg name="name" value="小李"></constructor-arg>
<constructor-arg name="age" value="98"></constructor-arg>
</bean>
SET
需要无参的构造函数
<bean id="user" class="cn.hp.entity.User">
<property name="name" value="小李"></property>
<property name="age" value="98"></property>
</bean>
注解注入
需要开启注解,不然无法识别
-
@Service :用于控制服务层的bean
-
@Controller:用于控制注册控制层的bean
-
@Repository:用于注册dao层的bean
-
@Component:可以用于注册所有的bean
//开启注解
<context:component-scan base-package="cn"></context:component-scan>
@Autowired+@Quelifier≈@Resource
Autowired通过类型进行注入 默认时必须存在要注入的类型,如果允许未null,那么可以结合配置required为false
Quelifier通过将@Qualifier注解与我们想要使用的特定spring bean的名称一起进行装配,Spring框架就能从多个相同类型并满足装配要求的bean中找到我们想要的
Resource通过名称进行注入,默认是当前类型的名称,也可以自己定义 name=""
AOP面向切面编程
AOP是OOP的延续,是软件开发的一个热点,也是Spring框架中的一个重要内容,是函数编程的一种衍生泛型。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
经典应用:事务管理、性能监视、安全检查、缓存、日志等
String AOP 使用纯Java实现,不需要专门的编译过程和类加载器,再运行期间通过代理方式向目标类织入增强代码。
Aspect|是一个基于java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,Aspect拓展了Java语言,提供了一个专门的编译器,再编译时对代码进行织入。
AOP开发中相关术语
详解,要想学习Aspect完成AOP开发, 必须了解AOP相关术语的含义。
- JoinPoint (连接点) :所谓连接点是指那些被拦截到的点,连接点指的是类中的方法。
- Pointcut (切入点) :指要对哪些“连接点”进行拦截,实际被增强的方法称为切入点。
- Advice (通知/增强) : 指拦截到”连接点”之后要做的事(就是增强的代码),通知分为前置通知、后置通知、环绕通知、最终通知、异常通知。
- Introduction (引介) :是一种特殊的通知,作用在类层面(了解)
- Target (目标) :代理的目标对象,被增强类的对象
- Weaving (织入) :指把增强应用到目标对象来创建新的代理对象的过程。
- Proxy (代理) : -个类被AOP织入增强后,产生-个代理对象。
- Aspect (切面) :是切入点和通知(引介)的结合。
代理=目标(连接点,切入点) + 切面(通知/增强) + 织入
代理模式
就是我再生成一个代理类,去代理UserController的saveUser()方法,代码大概就长这样:
class UserControllerProxy {
private UserController userController;
public void saveUser() {
checkAuth();
userController.saveUser();
}
}
这样在实际调用saveUser()时,我调用的是代理对象的saveUser()方法,从而实现了鉴权。
代理分为静态代理和动态代理,静态代理,顾名思义,就是你自己写代理对象,动态代理,则是在运行期,生成一个代理对象。
开启aop注解
<!--开启注解,确认扫描范围-->
<context:component-scan base-package=""/>
<!--注解实现aop,开启aop注解--><aop:aspectj-autoproxt/>
在切面层配置注解
@Component
@Aspect
@Before
@After
@Around("execution(* * *..*.*(..))")
第二种写法
//第一个*代表访问类型 第二个代表任意类型返回值
@Pointcut("execution(* * *..*.*(..))")
public void pointcut1();
@Before("pointcut1")
public void checkPurview2(){
System.out.println("权限访问");
}
Spring的事务管理
事务是一个不可分割操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态变到另一种一致性状态。
事务的特性
- 原子性:事务是不可分割的
- 一致性:事务执行前后数据完整性保持一致
- 隔离性:一个事物的执行,不应该受到其他事务的干扰
- 持久性:一旦事务结束,数据就持久到数据库
事务的并发问题
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
- 小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
事务隔离级别
可重复读:给数据上锁,不让别的事务做修改删除操作。
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
事物的传播行为
事务的传播特性
事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring定义了7中传播行为:
类型 | 说明 |
---|---|
propagation_requierd | 如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。 |
propagation_supports | 支持当前事务,如果没有当前事务,就以非事务方法执行。 |
propagation_mandatory | 使用当前事务,如果没有当前事务,就抛出异常。 |
propagation_required_new | 新建事务,如果当前存在事务,把当前事务挂起。 |
propagation_not_supported | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
propagation_never | 以非事务方式执行操作,如果当前事务存在则抛出异常。 |
propagation_nested | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。 |
事务的实现方式
- 编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。
- 基于 TransactionProxyFactoryBean的声明式事务管理
- 基于 @Transactional 的声明式事务管理
- 基于Aspectj AOP配置事务
事务的XML配置写法
导入jar
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
配置xml文件
<!--配置外部资源-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--连接数据库-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClass" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
</bean>
<!--配置事务管理器-->
<bean id="transaction" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务的传播方式-->
<tx:advice id="mytx">
<tx:attributes>
<tx:method name="find*" propagation="REQUIRED" isolation="DEFAULT"/>
<tx:method name="add"/>
</tx:attributes>
</tx:advice>
<!--配置切入点-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* *..*.*(..))"/>
<aop:advisor advice-ref="mytx" pointcut-ref="pointcut"/>
<!--aop:advisor和aop:aspect区别-->
</aop:config>