SpringIOC
注意:所有在xml配置的标签,如果调换标签位置报错,就证明对于标签顺序是有要求的,请查阅相关文档改正
一.IOC(xml在beans标签下的配置)
Inversion of Control
控制反转:把创建对象的的权利交给框架,是框架的重要特征
作用:降低程序耦合性
1.ioc使用:
获取spring的Ioc核心容器,并根据id获取对象
ApplicationContext的三个常用实现类:
- ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
//获取容器对象,指定配置文件的位置
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
- FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
- AnnotationConfigApplicationContext:它是用于读取注解创建容器的
2.容器
其实就是一个map集合,来放要用的封装对象
key是自己所绑定或给定的名字或别名
value是对于创建对象的方法或接口实现类
2.1核心容器的两个接口
核心容器的两个接口引发出的问题:
* ApplicationContext: 单例对象适用 采用此接口
* 它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
* BeanFactory: 多例对象使用
* 它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
3. spring的xml文件标签及属性
3.1创建Bean的三种方式:
第二、三种方法适用于导入别人的工程jar包,使用其中的特定方法来创建对象
- 使用默认构造函数创建。
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。 - 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
- 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
3.2bean的作用范围调整
bean标签的scope属性:
作用:用于指定bean的作用范围
取值: 常用的就是单例的和多例的
- singleton:单例的(默认值)
- prototype:多例的
- request:作用于web应用的请求范围
- session:作用于web应用的会话范围
- global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
3.3bean对象的生命周期
单例对象(立即)
- 出生:当容器创建时对象出生
- 活着:只要容器还在,对象一直活着
- 死亡:容器销毁,对象消亡
- 总结:单例对象的生命周期和容器相同
多例对象(延迟)
- 出生:当我们使用对象时spring框架为我们创建
- 活着:对象只要是在使用过程中就一直活着
- 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
4.依赖注入
依赖注入(依赖关系的维护):依赖关系的管理,以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明。注入适用于不经常变化的数据
4.1依赖注入数据及方式分类
能注入的数据:有三类
-
基本类型和String
-
其他bean类型(在配置文件中或者注解配置过的bean)
-
复杂类型/集合类型
用于给List结构集合注入的标签: list array set 用于个Map结构集合注入的标签: map props 结构相同,标签可以互换
注入的方式:有三种
- 使用构造函数提供
- 使用set方法提供(不能提供自己的构造器,使用默认的)
- 使用注解提供(相关的set方法就不用提供了)
4.1.1使用构造函数提供
使用的标签:constructor-arg
标签出现的位置:bean标签的内部
标签中的属性:
以下三个用于指定给构造函数中哪个参数赋值
- type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
- index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
- name:用于指定给构造函数中指定名称的参数赋值 (常用的)
这两个并不是赋值的
-
value:用于提供基本类型和String类型的数据
-
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
优势: 在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。 弊端: 改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
4.1.2 使用set方法提供(比构造函数注入更加常用一点)
涉及的标签:property
出现的位置:bean标签的内部
标签的属性:
-
name:用于指定注入时所调用的set方法名称
-
ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
-
value:用于提供基本类型和String类型的数据
优势: 创建对象时没有明确的限制,可以直接使用默认构造函数 弊端: 如果有某个成员必须有值,则获取对象是有可能set方法没有执行。
二.IOC(xml中context标签下的Annotation配置)
注入的方式:有三种
- 使用构造函数提供
- 使用set方法提供(不能提供自己的构造器,使用默认的)
- 使用注解提供
1.context的使用
首先引用官方文档下的context的命名空间和约束,然后使用context标签,它会扫描整个工程下使用注解的方法或接口
2.注释的分类
- 用于创建对象的
- 用于注入数据的
- 用于改变作用范围的
- 和生命周期相关 了解
2.1创建对象
他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的
-
Component:
作用:用于把当前类对象存入spring容器中
属性:value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。 -
Controller:一般用在表现层
-
Service:一般用在业务层
-
Repository:一般用在持久层
以上三个注解他们的作用和属性与Component是一模一样。
他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
2.2用于注入数据
他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的
- Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了,但也可以写在set方法上
注入bean的id是配置文件中类的首字母小写 - Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
属性:
value:用于指定注入bean的id。 - Resource:
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。 - Value:
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
2.3用于改变作用范围
他们的作用就和在bean标签中使用scope属性实现的功能是一样的
- Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值:singleton prototype
三.纯注解IOC,无xml配置文件
1.步骤
- 专门创建一个配置要使用注解的信息和要使用jdbc的信息给spring框架来确认,就等于代替了xml配置文件
- 将jdbc部分抽取出来作为一个基础类
- 使用spring的注解来完成相关配置
2.使用spring的注解配置替代xml
- Configuration
作用:指定当前类是一个配置类
细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。 - ComponentScan
作用:用于通过注解指定spring在创建容器时要扫描的包
属性:
value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
我们使用此注解就等同于在xml中配置了:
<context:component-scan base-package="com.lhjitem"></context:component-scan>
-
Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
属性:
name:用于指定bean的id。当不写时,默认值是当前方法的名称
细节:
当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。
查找的方式和Autowired注解的作用是一样的 -
Import
作用:用于导入其他的配置类
属性:
value:用于指定其他配置类的字节码。
当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类 -
PropertySource
作用:用于指定properties文件的位置
属性:
value:指定文件的名称和路径。
关键字:classpath,表示类路径下 -
value:里面书写EL表达式来获取对应的值
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
- EnableTransactionManagement:是开启事务管理的开关注解
四.使用spring-test代替传统junit
使用Junit单元测试:测试我们的配置
Spring整合junit的配置:
- 导入spring整合junit的jar(坐标)
- 使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
@Runwith
- 告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
@ContextConfiguration
locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在地位置
当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
SpringAOP
一.AOP(面向切面编程)
AOP的专业术语
- 切入点:就是业务层的各种业务方法
AOP的作用及优势
作用:
- 在程序运行期间,不修改源码对已有的方法进行增强
优势:
- 减少重复代码、提高开发效率、维护方便
二.SpringAOP
0.切入点表达式的写法
- 关键字:execution(表达式)
- 表达式:访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
- 标准的表达式写法:
public void com.lhjitem.service.impl.AccountServiceImpl.saveAccount()
注意!!
在实际开发中表达式的写法为:切到业务层实现类下的所有方法
0.1相关省略写法(需要导aspectj的jar包)
- 访问修饰符可以省略
- 返回值可以使用通配符(*),表示任意返回值
- 包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
- 包名可以使用…表示当前包及其子包
- 类名和方法名都可以使用*来实现通配
- 参数列表:
可以直接写数据类型:
*基本类型直接写名称
*引用类型写包名.类名的方式
*可以使用通配符表示任意类型,但是必须有参数
*可以使用…表示有无参数均可,有参数可以是任意类型
如果这些省略全部用上极致省略写法为:
<aop:config>
<!--配置通用表达式-->
<aop:pointcut id="pc" expression="execution(* com.lhjitem.service.impl.*.*(..))"/>
<!--建立事务通知和切入点表达式的对应关系-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pc"></aop:advisor>
</aop:config>
* *..*.*(..)
1.说明
AOP总的来说就是高级版的事务管理
我们之前一直用的是事务管理器的内部逻辑代码都是采用自己编码的类来完成,但其实spring框架为我们提供了一个事务管理器类DataSourcetransactionManager,在xml中直接配置就好
通过配置的方式,实现功能
- 通过xml
- 通过注解
2.spring中基于XML的AOP配置步骤
-
首先引用官方文档下的aop的命名空间和约束
-
把Bean(即重复代码类)交给spring来管理
-
使用aop:config标签表明开始AOP的配置
以下提到的标签配置都要在aop:config标签下进行 -
使用aop:aspect标签表明配置切面
* id属性:是给切面提供一个唯一标识
* ref属性:是指定通知类bean的Id。 -
在aop:aspect标签的内部使用对应标签来配置通知的类型
· aop:before:表示配置前置通知
* method属性:用于指定Logger类中哪个方法是前置通知
* pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
· aop:after-returning:表示配置后置通知
* method属性:用于指定Logger类中哪个方法是前置通知
* pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
· aop:after-throwing:表示配置异常通知
* method属性:用于指定Logger类中哪个方法是前置通知
* pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
· aop:after:表示配置最终通知
* method属性:用于指定Logger类中哪个方法是前置通知
* pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强 -
使用point-cut标签单独配置切入点表达式,然后在通知标签中使用pointcut-ref来引用point-cut标签
-
在相关页面加上@Aspect注解,表示我们要使用切面编程
注意:这四个通知的执行顺序是:Before->After->AfterReturning->AfterThrowing
由于执行顺序所带来的异常建议使用”环绕通知“来解决!
2.1spring中的环绕通知
1.定义:
-它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。所以通知既可以通过xml方式配置,还可以通过自己编码的方式配置。
2.Spring框架为我们提供了一个接口ProceedingJoinPoint:
该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
* 该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
3.实现代码示例(输出位置的区别就是不同种的通知类别)
这些代码是定义在事务管理类中
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
//1.得到方法执行所需的参数
Object[] args = pjp.getArgs();
//2.开启事务
this.begin();
//3.明确调用业务层方法(切入点方法)
rtValue = pjp.proceed(args);
//4.提交事务
this.commit();
return rtValue;
}catch (Throwable t){
//5.回滚事务
this.rollback();
throw new RuntimeException(t);
}finally {
//6.释放资源
this.release();
}
}
3.spring中基于XML与注解的AOP配置步骤
- .首先引用官方文档下的aop-context的命名空间和约束
- .配置context标签来确认创建容器要扫描的包
- 在相关页面加上@Aspect注解,表示我们要使用切面编程
- 进行相关配置,注解的使用可参考二.IOC(xml中context标签下的Annotation配置) 这一节
- 切入点表达式注解@Pointcut(“execution(表达式)”)
@Pointcut("execution(* com.lhjitem.service.impl.*.*(..))")
private void pt1(){}
//引用时必须加括号
- 四类通知类型的注解@Before、@After-returning、@After-throwing、@After
- 环绕通知的注解@Around
- 在xml种配置spring开启注解AOP的支持:
使用该标签"<\aop:aspectj-autoproxy>"
4/5.spring基于xml/注解配置声明式事务管理步骤
1.说明
这个对于2/3来说改进采用了spring提供的事务管理器,而不再使用自己定义的事务管理器
2.优缺点
- 对于使用xml来说可以针对任何方法一步到位的配置事务属性
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
- 而对于注解来说需要精确到每个方法的时候需要在每个方法前使用@Transactional来单独配置
2.spring基于xml配置声明式事务管理步骤
- 配置事务管理器
- 配置事务的通知
此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用 - 配置AOP中的通用切入点表达式
- 建立事务通知和切入点表达式的对应关系
- 配置事务的属性(是在事务的通知tx:advice标签的内部)
2.1配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
3.spring基于注解配置声明式事务管理步骤
- 配置事务管理器
- 开启spring对注解事务的支持
- 在需要事务支持的地方使用@Transactional注解