spring复习
spring复习spring复习一、spring简介1.Spring 中常用术语:2、Spring 的优势3、spring能帮我们做什么4、spring框架的结构二、IOC容器1.首先聊聊控制反转2.生活举例3.构造器注入4.set 方法注入5.Bean的作用域6.自动装配6.1、按照名字自动装配6.2、按照类型自动装配7.注解开发(常用)准备工作使用注解常用的注解第一组,自动装配第二组,分层开发
spring复习
一、spring简介
1.Spring 中常用术语:
1.1框架:是能完成一定功能的半成品。
框架能够帮助我们完成的是:项目的整体框架、一些基础功能、规定了类和对象如何创建,如何协作等
1.2非侵入式设计:
从框架的角度可以理解为:无需继承框架提供的任何类,这样我们在更换框架时,之前写过的代码几乎可以继续使用
1.3轻量级和重量级:
轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、 部署简单等等,其实就是比较容易使用,而重量级正好相反
1.4容器:
在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、 拿出等操作,所以容器还要管理对象的生命周期(拿来即用,方便统一管理)
1.5bean:
把Bean理解为 类的代理或代言人(实际上确实是通过反射、代理来实现的),这样它就能代表类拥有该拥有的东西了;
凡是子类及带属性、方法的类都注册Bean到Spring中,交给它管理
2、Spring 的优势
- 低侵入 / 低耦合 (降低组件之间的耦合度,实现软件各层之间的解耦)
- 声明式事务管理(基于切面和惯例) 方便集成其他框架(如MyBatis、Hibernate)
- Spring 框架中包括了 J2EE 三层的每一层的解决方案(一站式)
- 降低 Java 开发难度
3、spring能帮我们做什么
- Spring 能帮我们根据配置文件创建及组装对象之间的依赖关系。
- Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
- Spring 能非常简单的帮我们管理数据库事务。
- Spring 还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套 JDBC访问模板来方便数据库访问。
- Spring 还提供与第三方Web(如Struts1/2、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
- Spring 能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。
4、spring框架的结构
二、IOC容器
1.首先聊聊控制反转
- 这不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框 架来管理。
- 以往的思路:若要使用某个对象,需要自己去负责对象的创建
- 反转的思路:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创 建过程,也就是把创建对象的控制权反转给了Spring框架
2.生活举例
过年了,需要给家里打扫个卫生,于是想请几个钟点工来擦擦玻璃。
解决方案:
1、自己主动的去,询问查找,看看谁认识钟点工,有了联系方式后,自己打电话邀约,谈价钱
2、直接打电话给家政公司,提出要求即可。
那么家政公司从哪里来?
1、自行构建 :我们可以使用配置文件,或者注解的方式定义一下咱们自己的容器里存放的东西。
2、使用别人的 :一定会有很多有钱人,成立自己的各类公司,他们的这些服务都可以集成在咱们的容器里,为我们提供很多强大的功能,比如spring自带的就很多template模板类。
3.构造器注入
编写javaBean
public class Dog {
private String name;
private int age;
public Dog(){}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name;}
public void setName(String name) {
this.name = name;
}
public int getAge() { return age; }
public void setAge(int age) {
this.age = age;
}
}
有参构造
注:id是自定义名字(一般为实体类名小写),后面.getBean(“dog”)中的名字与之对应
<!-- 推荐使用,根据名字注入 -->
<bean id="dog" class="com.xinzhi.entity.Dog">
<constructor-arg name="name" value="goldilocks"/>
<constructor-arg name="age" value="11"/>
</bean>
<!-- 直接注入也是按顺序注入,了解 -->
<bean id="dog" class="com.xinzhi.entity.Dog">
<constructor-arg value="goldilocks"/>
<constructor-arg value="11"/>
</bean>
<!-- 按照参数类型注入,了解 -->
<bean id="dog" class="com.xinzhi.entity.Dog">
<constructor-arg type="java.lang.String" value="goldilocks"/>
<constructor-arg type="java.lang.Integer" value="11"/>
</bean>
4.set 方法注入
注:要求被注入的属性 , 必须有set方法 。
实体类
@Data
public class Address {
private String addressInfo;
}
@Data
public class User implements Serializable {
private String name;
private Address address;
//爱好
private String[] hobbies;
//职务
private List<String> duties;
//家庭关系
private Map<String,String> familyTies;
//购物车商品
private Set<String> carts;
//工作经历
private Properties workExperience;
//女儿
private String daughter;
}
set注入(property 相当于调用了我们的setter方法)
<bean id="address" class="cn.itnanls.Address" >
<property name="addressInfo" value="珠琳旺角大厦"/>
</bean>
<bean id="user" class="cn.itnanls.User">
<!-- 基本属性注入 -->
<property name="name" value="小白" />
<!-- 引用类型注入(也可以使用自动装配,下面有介绍) -->
<property name="address" ref="address"/>
<!-- 数组注入 -->
<property name="hobbies">
<array>
<value>写程序</value>
<value>漂亮姑娘</value>
<value>赢钱</value>
</array>
</property>
<!-- list注入 -->
<property name="duties">
<list>
<value>IT老师</value>
<value>互联网从事人员</value>
</list>
</property>
<!-- set注入 -->
<property name="carts">
<set>
<value>纸尿裤</value>
<value>玩具</value>
</set>
</property>
<!-- map注入 -->
<property name="familyTies">
<map>
<entry key="father" value="某某1" />
<entry key="mather" value="某某2" />
</map>
</property>
<!-- property注入 -->
<property name="workExperience">
<props>
<prop key="first">电厂职工</prop>
<prop key="second">java开发工程师</prop>
<prop key="third">java讲师</prop>
</props>
</property>
<!-- null注入 -->
<property name="daughter">
<null/>
</property>
</bean>
测试
@Test
public void testDI(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
//User user = applicationContext.getBean(User.class);
//或者如下这种
User user = (User)applicationContext.getBean("user");
System.out.println(user);
}
5.Bean的作用域
Spring IOC容器创建一个Bean实例时,可以为Bean指定实例的作用域,作用域包括singleton(单例模式)、prototype(原型模式)、request(HTTP请求)、session(会话)、global-session(全局会话)。
6.自动装配
spring作为长期以来java最火的框架,其IOC做的十分的健全,以上情况都是我们手动装配,但是我们也 说了spring及其灵活的帮助我们完成了解耦工作,如果所以的类都是自己手动完成注入,他的解耦能力 就不会体现的那么强烈了,于是spring还为我们提供了自动装配的能力
6.1、按照名字自动装配
修改bean配置,增加一个属性 autowire=“byName”;
过程:
从javabena的set方法获取名字,如setAddress,就去spring容器中找名字为address的bean(通过实体类中的某个字段名和所需要的bean的id相同进行匹配),如果有,就取出注入;如果没有,就不注入。
//id="address",如果和user实体类中的字段名不一样就匹配不了
<bean id="address" class="cn.itnanls.Address" >
</bean>
<bean id="user" class="com.xinzhi.entity.User" autowire="byName">
//...中间省略,也不用手动注入address
</bean>
6.2、按照类型自动装配
修改bean配置,增加一个属性 autowire=“byType”
过程:
根据class="cn.itnanls.Address"自动装配,当然不可以同时出现既按照类型和名字都可以完成装配的
//id="address",如果和user实体类中的字段名不一样就匹配不了
<bean id="address555" class="cn.itnanls.Address" >
</bean>
<bean id="user" class="com.xinzhi.entity.User" autowire="byType">
//...中间省略,也不用手动注入address
</bean>
7.注解开发(常用)
注解只是个标识,我们需要去解析他。 所以要让注解生效,还需要进行一个配置。在运行前,扫描一下所有的文件,看看哪些类头上戴了注解。 自己写扫描文件的方法太麻烦,spring当然提供了方式。
准备工作
1、配置文件需要加头文件(context相关的配置)
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
>
2、在配置文件中加次注解,就是告诉spring【cn.itnanls】下的类都扫描一下看看
<context:component-scan base-package="cn.itnanls"/>
此时准备工作做完了,只需加入相应的注解就行
使用注解
1.修改文件,在user的address属性上加注解@Autowired
注:@Autowired先按类型匹配,没有匹配到则按照名字匹配
@Autowired
private Address address;
2.删除user配置文件中的address注入(这时就不需要下面这个了)
<!-- 引用类型注入 -->
<property name="address" ref="address"/>
3.测试。。。
常用的注解
第一组,自动装配
1.@Autowired
@Autowired先按类型匹配,没有匹配到则按照名字匹配
2.@Qualifier
@Qualifier不能单独使用,它和@Autowired配合可以根据名称(bean中的id)进行自动装配
例:
@Qualifier(value = "cat2")
private Cat cat;
3.@Resource
@Resource是javaee的注解
@Resource如有指定的name属性,先按该属性进行byName方式查找装配
其次再进行默认的byName方式进行装配
如果以上都不成功,则按byType的方式自动装配
都不成功,则报异常
例子:
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
第二组,分层开发
@Controller 控制层
@Service 业务层
@Repository Dao层
其实一个注解都能搞定,@Bean能代替所有,但是应为分层的原因,使用不同的注解可读性更高。 这些注解就是在容器启动时生成bean,和配置文件的作用一样。
第三组,组件开发
@Component
@Value
例子:
@Component
public class Student {
@Value("张三")
private String name;
@Autowired
private Address address;
}
第四组,配置文件
@Configuration
@Bean
@Configuration
public class AnimalConfig {
@Bean
public Mouse mouse(){
Mouse mouse = new Mouse();
mouse.setAge(12);
mouse.setName("jerry");
return mouse;
}
//参数是你要注入的其他的bean
@Bean
public Cat cat(Mouse mouse){
Cat cat = new Cat();
cat.setAge(5);
cat.setName("Tom");
cat.setFood(mouse);
return cat;
}
}
小结:很多注解的功能都是一样的,都是讲javabean注入到容器,只是多种多样的注解使得我们的语义化更加友好
8.生命周期
9.懒加载
例:
<bean id="address" class="cn.itnanls.Address" lazy-init="true"/>
用到就加载,不用就不加载,默认是及时加载
三、AOP
1.什么是AOP
- AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统 层面上的问题,比如日志,事务,权限等待。
- 在不改变原有逻辑的基础上,增加一些额外的功能。代理也是这个功能。
- AOP技术利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个 类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是 那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降 低模块之间的耦合度,并有利于未来的可操作性和可维护性。
长话短说:就是有这样的需求,在某一些类中,增加很多统一的代码,比如,日志,事务,权限等。
2.AOP的相关名词
1.通知、增强处理(Advice)
通知、增强处理(Advice) 就是你想要的功能,也就是上说的安全、事物、日子等。你给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码
2.连接点(JoinPoint)
连接点(JoinPoint) 这个就更好解释了,就是spring允许你是通知(Advice)的地方,那可就真多了, 基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点。只要记住,和方法有关的前前后后都是连接点。
3.切入点(Pointcut)
切入点(Pointcut) 具体要要执行的连接点(连接点有很多,但是真正的去执行的连接点就是我们的切入点)
4.切面(Aspect)
切面(Aspect) 切面是通知和切入点的结合。
5.引入(introduction)
引入(introduction) 允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通 知定义的)用到目标类中吗(描述的是一种过程)
6.目标对象(TargetObject)
目标对象(TargetObject) 引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况 下,被咱们织入切面。而自己专注于业务本身的逻辑。
7.织入(weaving)
织入(weaving) 把切面应用到目标对象来创建新的代理对象的过程。
3.练习
1.自定义类和方法实现
第一步 : 写我们自己的一个切入类(MyAop.class)
public class MyAop {
public void before(){
System.out.println("执行方法之前打印一条日志! -- 自定义形式");
}
public void after(){
System.out.println("执行方法之后打印一条日志! -- 自定义形式");
}
}
第二步去spring中配置
//加入头文件
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<!--注册bean-->
<bean id="myAop" class="com.xinzhi.aop.MyAop"/>
<!--aop的配置-->
<aop:config>
<!--使用AOP的标签实现一个切面-->
<aop:aspect ref="myAop">
<aop:pointcut id="pointcut" expression="execution(*com.xinzhi.service.impl.*.*(..))"/>
<aop:before pointcut-ref="pointcut" method="before"/>
<aop:after pointcut-ref="pointcut" method="after"/>
</aop:aspect>
</aop:config>
2.注解实现(当下主流)
第一步:编写一个注解实现的增强类
@Component
@Aspect
public class AnnotationAOP {
//springaop自动的5种aop这里全部列出
@Before("execution(* com.xinzhi.service.impl.*.*(..))")
public void before(){
System.out.println("---------方法执行前before()---------");
}
@After("execution(* com.xinzhi.service.impl.*.*(..))")
public void after(){
System.out.println("---------方法执行后after()---------");
}
@AfterReturning("execution(* com.xinzhi.service.impl.*.*(..))")
public void afterReturning(){
System.out.println("---------方法返回后afterReturning()---------");
}
@Around("execution(* com.xinzhi.service.impl.*.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("-------环绕前-------");
System.out.println("签名(拿到方法名):"+jp.getSignature());
//执行目标方法proceed
Object proceed = jp.proceed();
System.out.println("-------环绕后------");
System.out.println(proceed);
}
@AfterThrowing("execution(* com.xinzhi.service.impl.*.*(..))")
public void afterThrow() {
System.out.println("--------------有异常发生-----------------" + new Date());
}
}
第二步:在Spring配置文件中,注册bean,并增加支持注解的配置
<aop:aspectj-autoproxy/>
注:定义切入点表达式execution ( com.sample.service.impl…(…))*
execution()是最常用的切点函数, 整个表达式可以分为五个部分:
- execution(): 表达式主体。
- 第一个号:表示返回类型,号表示所有的类型。
- 包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包, com.sample.service.impl包、子孙包下所有类的方法。
- 第二个号:表示类名,号表示所有的类。
- (…):最后这个星号表示方法名,号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任 何参数。
四、整合MyBatis
动态Mapper(常用)
配置文件:
<!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<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>
<!-- Mapper 扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描 cn.wmyskxz.mapper 包下的组件 -->
<property name="basePackage" value="com.xinzhi.dao"/>
</bean>
<!--配置SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--关联Mybatis-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations"
value="classpath:com/xinzhi/dao/*.xml"/>
</bean>
企业的做法 一般使用动态mapper,使用动态代理完成工作,一般会使用xml和mappeer配合使用。这才是最佳实践。
五、声明式事务
1、事务特性
- 原子性(Atomicity):事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要 么都执行失败。
- 一致性(Consistency):事务执行的结果必须是使数据库数据从一个一致性状态变到另外一 种一致性状态。当事务执行成功后就说数据库处于一致性状态。如果在执行过程中发生错误, 这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这是数据库就处于不一致状 态。
- 隔离性(Isolation):一个事务的执行过程中不能影响到其他事务的执行,即一个事务内部 的操作及使用的数据对其他事务是隔离的,并发执行各个事务之间无不干扰。
- 持续性(Durability):即一个事务执一旦提交,它对数据库数据的改变是永久性的。之后 的其它操作不应该对其执行结果有任何影响。
2.Spring中的事务管理
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以 使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
2.1编程式事务管理
将事务管理代码嵌到业务方法中来控制事务的提交和回滚 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
2.2声明式事务管理 (常用)
一般情况下比编程式事务好用。 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
2.3声明式事务管理举例
2.3.1注解的形式
头文件的约束导入 : tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 开启事务注解,并配置一个事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
加注解:
@Service
@Transactional
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
public void transaction() {
userMapper.addUser(new User(100,"ITbai","123"));
int i = 1/0;
userMapper.updateUser(new User(100,"ITbai","234"));
}
}
2.3.2配置文件进行声名式事务的配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(*com.xinzhi.service.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
2.4spring事务传播特性
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这 个事务中,这是最常见的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 propagation_required类似的操作
注:Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。前三种常用,其他一般不使用
最后张口松耦合,闭口高内聚
更多推荐
所有评论(0)