**
IOC
控制反转:new 对象的操作交给spring容器来使用 使用xml配置或者注解配置就可以直接注入
**
#####bean名称空间######
使用: bean对象一定要有无参构造
在创建Spring容器ApplicationContext对象时候创建bean对象(默认)
调用getBean多次 也只会创建同一个bean对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- bean标签用于配置一个组件对象(javaBean,Dao,Service)
id 是给bean对象起一个唯一的标识
class bean对象的具体全类名
-->
<bean id="p1" class="com.xxx.Person">
property标签用来配置属性信息 ~~走无参的构造方法 通过set方法注入~~
name 是属性名
value 是属性值
ref 是引用bean中的bean对象所对应的bean配置的id
也可以使用property的内部标签(只可以在内部赋值的时候使用 无法通过spring容器获取):
**1** bean标签来注入bean属性
**2** list 标签专门赋值 list属性
**3** map标签 entry赋值 map属性
**4** prop标签
还可以通过name属性利用级联属性赋值 内部类.属性 (这样使用的前提是先利用ref赋值 才能进行修改)
<constructor-arg name="构造参数中的名字" ~~走有参的构造方法 通过构造器注入~~
value=""
index="构造参数中的第几个参数 从0开始"
type=“可以在有多个构造器的时候指定具体的类型来选择其中一个构造器”
>
</bean>
</beans>
使用java代码创建:
(可以用FileSystemXmlApplicationContext从项目工程路径下查找配置文件 或者 ClassPathXmlApplicationContext对象从类路径下查找)
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:你的xml.xml");
Person person = applicationContext.getBean();
**归纳getBean**
1用id从ioc容器中获取bean找单独的一个
2用类名.class根据bean的类型从ioc容器中获取bean 此时如果有多个同class类型的对象就会出错
######p名称空间########
<bean id="p1" class="com.xxx.Person" p:你的类属性="你的类属性的值">
######util名称空间########
<util> 可以定义外部的list map properties set等 在bean中同样使用property的ref来引用 也可以单独的使用
######通过静态工厂方法创建的bean####### 工厂类创建类的作用就是解耦 注入的或者spring容器代码产生的是你需要的类而不是工厂类~
1先写一个类作为工厂类
2写一个静态的方法 里头创建对象并且返回
3 bean标签 class是工厂类的全类名 factor-method是2中的静态方法
4依然使用相关的代码创建
######通过实例工厂方法创建的bean#######
1写的方法变成普通成员方法
2bean标签 配置工厂类实例
3再写一个bean 配置factory-bean 为2中bean的id factory-method为1中的成员方法
######FactoryBean接口方式创建对象######
1实现FactorBean范型是你要创造的类
2实现三个方法 并返回创建的对象
3写bean(配置的是你实现FactorBean的类) 后就可以直接注入范型中的类
spring中配置bean的时候可以通过property标签name是你的属性的名字经过set方法将你的属性参数赋值进去
######通过继承实现bean配置信息的重用######
bean标签中用parent引用bean的id 就可以继承 自己写上自己相应的附加代码 就可以完成
######通过abstract属性创建一个模版bean######
从此以后这个bean对象就不可以直接实例化咯~而是最为被引用的模版
*****容器对象创建后 里头bean对象的顺序******:
1在xml中配置的bean对象 默认在创建Spring容器时候都会创建
2 bean标签中可以用depends-on属性来标志对象创建间的顺序
要先创建depends-on的对象后才可以创建自己(depends-on对象可以加很多个参数)
******scope 属性设置范围*******
singleton 默认情况 是singleton,表示Spring容器中只有一个单例
单例是在Spring容器创建的时候。初始化所有单例Bean对象
并且每次调用Bean对象的时候,还是原来Spring容器中的对象 并不会重新创建
prototype prototype是表示当前配置的Bean对象是多例。
在Spring容器被创建的时候,bean不会被创建出来。
并且每次调用getBean方法都会创建一个对象实例
request 表示一次请求内,不管调用几次getBean方法,返回的都是同一个bean对象
Object bean = request.getAttribute(xxx);
if (bean == null) {
bean = 创建一个
request.setAttribute(xxx,bean);
}
session 表示一个Session对象内,不管调用几次getBean方法,返回的都同一个Bean对象
Object bean = session.getAttribute(xxx);
if (bean == null) {
bean = 创建一个
session.setAttribute(xxx,bean);
******xml的自动装配*******
bean标签的autowire属性
autowire 设置自动装配的方式
default 和 no 一样,都表示不装配, 如果对象不你手动设置,就没有值。
byName 表示Spring容器会自动按照子对象的属性名,来查找这个id的bean对象。
byType 表示Spring容器会自动的按照子对象的类型去查找bean对象注入。
找到一个,就注入
没有找到,值就为null
找到多个,就报错。
constructor 表示Spring容器会按照子对象的类型去查找构造方法,中参数需要的类型去注入。
先按照类型查询,如果找到一个就注入。
如果找到多个,再按照构造方法中参数的变量名做为id来查找,如果找到就注入。如果没有找到,就为null
如果没有找到,值也为null
如果没有构造方法就会找无参的构造方法
******创建带有生命周期方法的bean******
利用bean标签的init-method 和 destroy-method(容器执行close方法的时候调用)
******bean的后置处理器******
1实现BeanPostProcessor
2写bean标签
配置好后xml中的bean都会从上至下执行带有后置处理器的操作
可以在后置处理器中配置动态代理并将代理对象返回 就可以实现增加的代理了~
**
使用spring管理数据库连接池
**
方式一:
1 bean标签里面class写自己的连接池对象 我用的是ComboPooledDataSource property写上name value配置你的数据库属性
2用ClassPathXmlApplicationContext来获取对象
方式二:引用的外部properties文件
1 bean标签class写的是PropertyPlaceholderConfigurer 可以加载jdbc属性配置文件
2 property 中name写location value写:classpath:你的路径 (一定要这样写 ClassPathXmlApplicationContext可以不写因为就是默认搜索类路径的)
3仍然要用方式一写一个bean
4 value的值写的是${配置文件对应的属性名称}
方式三: 使用Context名称空间加载jbdc.properties属性配置文件
1 标签是 context:property-placeholder location写上classpath:你的路径 这样子就可以加载属性配置文件了
**
spring EL 表达式:主要功能就是赋值
**
一般都是使用在 property属性的value里面的
1 使用字面量 格式:#{数值} #{“字符串” || ‘字符串’}
2 引用其他bean 格式:#{bean的id}
3 引用其他bean的某个属性值 格式: #{bean.属性名}
4 调用非静态方法 格式: #{bean.方法名(参数)}
调用的是你的pojo对象中的非静态方法的返回值进行赋值(需要写写一个bean配置你的pojo)
5 调用静态方法 格式:#{T(全名类).方法名(参数)}
调用的是你的pojo对象中的静态方法的返回值进行赋值
6 使用运算符 格式:#{表达式,例如乘除法}
**
注解功能:很经常使用很重要哦~
**
使用注解需要aop包
@Controller 专门标注给web层的组件
@Service 专门给Service层的组件注解
@Repository 给Dao层组件标注
@Component 给Dao、Service、控制器Web层之外的组件进行标注。
@Scope 可以修改bean的Scope属性,默认不标注此注解表示单例。 也可以通过注解修改为多例@Scope(value="prototype")
使用
1在你的类上面使用注解
2在spring配置文件中加上包扫描 <context:component-scan base-package="扫描的包包含子包"></context:component-scan>
3使用 ClassPathXmlApplicationContext进行调用
所形成的id默认是你的类名首字母小写,可以利用注解的value进行手动设置
*****指定包扫描的时候所需要过滤的内容******
使用context:include-filter标签指定扫描包时要包含的类 首先要设置use-default-filters属性设置为false取消默认扫描包下全部的规则
使用context:exclude-filter标签指定扫描包时不包含的类
标签里面的type属性一般使用两个值 : annotation表示利用注解来标志需要排除还是加入 assignable表示利用类(包含子类)来标志需要排除还是加入
*******使用@autowired注解实现根据类型自动装配**********
Autowired注解标注的方法和对象属性都是初始化的时候 就调用 注入了!
1标注对象属性:
spring容器会自动根据对象的【类型】到spring容器中去查找 然后注入值
1如果找到一个就直接注入值
2若果找到了多个 spring容器就会自动按照@Autowired的变量名称作为id来查找
**@Qualifer()注解加在@autowired之上:可以根据指定的id去spring容器中查找 然后注入
**autowired的required属性:
默认值是true 表示被标注的bean对象必须要有值注入 如果找不到注入 就报错
false:允许找不到 值就是null
2 标注方法:
在方法上面写@Autowired注解 在初始化的时候该方法就会直接调用(但是方法上的autowired注解的required属性如果是false并且找不到可以注入的参数位置的对象 就不会调用该方法)
可以在方法的参数位置写上Spring容器里扫描到的类 也会自动注入(@Qualifer注解也可以使用)
**
范型的依赖注入:
**
其实概念很简单:
1我们写一个父抽象类带有范型T
2不同子类有具体的不同范型
3当我们从容器中注入2中的对象的时候 就会根据2中不同的范型去查找相对应的1中的对象,即确定子类范型的时候 抽象父类的范型就会确定下来 并且一般此时容器中有几个不同的范型的对象 所以需要哪个就可以匹配哪个~
**
Spring专有的测试:用注解代替ClassPathXmlApplicationContext的功能
**
1写一个类 标注@ContextConfiguration(locations="classpath:你的spring配置文件") 和 @RunWith(SringJunit4ClassRunner.class)
2可以写autowire 注入你想要的容器中扫描到的对象~
**
AOP:面向切面编程
**
******首先介绍******
程序是运行期间 动态地将某段代码插入到原来方法代码的某些位置中并且不需要对源代码进行改变 这就叫做面向切面编程(类似于动态代理~)
我们可以使用jdbc动态代理实现这个功能
CGLIB对类进行代理 而不是接口 可以在没有接口的情况下同样实现代理的效果 (jdbc动态代理是对接口进行代理)
然而spring框架就是整合了这些的提供了AOP,目标对象实现了接口就是采用jdbc动态代理 如果没有实现接口就是用的CGLIB代理,用@autowired注入增强对象的时候要注意jdbc只能用接口来接收 CGLIB就类接收
******AOP 用注解的方式实现******
通知(Advice) 增强的代码。比如前置增强的代码,后置增强的代码,异常增强代码。
切面(Aspect) 包含有通知代码的类叫切面
横切关注点 就是可以添加增强代码的位置。比如前置位置,后置位置,异常位置。和返回值位置。
目标(Target) 被代理的对象。
代理(Proxy) 增强之后的那个对象
连接点(Joinpoint) 连接点指的是横切关注点和程序代码的连接,叫连接点。
切入点(pointcut) 用户真正处理的连接点
在Spring中切入点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
使用:
1将切面和目标都扫描进入spring容器 并且加入<aop:aspectj-autoproxy></aop:aspectj-autoproxy>允许spring支持@Aspect注解方式进行自动代理
2切面类加@Aspect注解和横切关注点注解(@Before(切入点表达式) @AfterReturning @After @AfterThrowing)
切入点表达式:execution(访问权限 返回值类型 方法全限定名(参数类型列表)) 访问权限只有public可以拦截到 可以不写
--限定符: * (1)匹配某全类名下多个方法 (2)xxx* 匹配类下的xxx打头的方法 (3)匹配任意类型返回值 (4)匹配一层任意子包 (5)匹配任意类型参数
.. (1)匹配任意多个子包 (2)任意类型的参数(目标对象没有参数也成立)
--与非运算:&&两个条件同时满足 ||两个条件只需要满足一个
*****通知的执行顺序*****
正常情况:前置通知 后置通知 返回值之后
异常情况:前置通知 后置通知 抛异常通知
*****JointPoint获取连接点信息:方法名和参数******
getSignature().getName()获取目标对象方法名
getArgs()获取目标对象方法参数
*****获取目标方法的返回值和异常*******
获取目标方法的返回值:横切关注点注解里面加入returning= "切面类方法自定义的方法参数 会把结果赋值到这个参数中"
获取目标方法的异常:横切关注点注解里面加入throwing=“切面类方法的Exception对象 会把异常对象赋值到这个参数中”
*****环绕通知******
也是切面累的一个方法 但是注解用的是:@Around(切入点表达式) 注意⚠️:必须要有返回值
@Around(value = "execution(public int ccc.xxx.interfaces.impl.aa.*(int, int))")
public static Object around(ProceedingJoinPoint pjp) throws Throwable { //用一个环绕通知实现四个通知的功能
Object result = null;
try {
try {
System.out.println("这是环绕的前置通知");
// 执行目标方法
result = pjp.proceed(pjp.getArgs());
} finally {
System.out.println("这是环绕的后置通知");
}
System.out.println("这是环绕的返回通知 ");
return result;
} catch (Exception e) {
System.out.println("这是环绕的异常通知");
throw e;
}
}
(1)如果环绕通知和单个的通知一起使用,顺序是:以目标函数的执行为分界线:环绕通知 单个通知 目标方法 环绕通知 单个通知
(2)环绕通知返回值的作用就是给其他单个通知接收的 否则其他单个通知中不会有返回值
(3)环绕通知的异常必须要往外抛 否则单个的异常通知接收不到
*****切入点表达式的复用******
1在切面类中写一个方法
2用@Pointcut(切入表达式)标志这个注解
3在切面类中需要用到切入点表达式的地方的值写成1中的 方法名()
*****多个切面多个通知的执行顺序*******
默认由切面类的首字母顺序决定执行顺序:(是一种先执行的通知包围后执行的结构)
1先执行的前置 后执行的前置
2目标方法
3后执行的后置和返回结果 先执行的后置和返回结果
也可以用@Order(数值 越小越优先)注解放在@Aspect上自定义顺序
*****用xml的方式实现AOP******
1写两个个bean class分别是你的目标对象 切面类
2
<aop:config>
<aop:pointcut expression="execution(public int aaa.ccc.interfaces.impl.ddd.*(int, int))" id="pointcut1"/> 通用的切入点表达式
<aop:aspect ref="你的切面类的id" >
<aop:before method="logBefore" pointcut-ref="pointcut1"/>
<aop:after method="logAfter" pointcut-ref="pointcut1"/>
<aop:after-returning method="logAfterReturning" pointcut-ref="pointcut1" returning="result"/>
<aop:after-throwing method="logAfterException" throwing="e" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
**
Spring访问数据库
**
<!-- 加载jdbc配置文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据库连接池对象 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
<property name="driverClass" value="${jdbc.driverClass}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
</bean>
然后在测试中注入@AutoWired DataSource对象就可以获取连接了
<!-- jdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
然后在测试中注入@AutoWired JdbcTemplate 对象就可以获取连接了
update更新一个
batchUpdate批量插入
queryForObject查询一个对象 或者一个数值(例如最大值最小值)
query查询出几条数据返回LIst
*****用hashmap装载具名参数执行具名sql语句****
具名sql语句就是?占位符写成 :名字 的形式
<bean id="namedParameterJdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg index="0" ref="dataSource" />
</bean>
@Autowired注入一个NamedParameterJdbcTemplate对象即可使用 调用update方法 参数是一个hashmap 键是匿名参数的值
************创建自己的DAO**********
方式1: 扫描你的DAO对象到容器里 注入jdbcTemplate对象 在要用的地方注入你的DAO
方式2: 扫你的DAO对象到容器里 你的DAO继承jdbcDaoSupport
写一个方法拥有注解@Autowired参数是JdbcTemplate 里面调用来自父类的setJdbcTemplate方法
调用getJdbcTemplate()方法获取所需要的对象然后就可以操作数据库了
**
声明式事务
就是通过注解的形式对事务的各种特性进行控制和管理 spring基于AOP完成声明示事务
**
**首先回忆下编码式的事务**
Connection conn = JdbcUtils.getConnection()
try{
conn.setAutoCommit(false);
jdbc操作
conn.commit() 提交事务
}catch (Exception e){
conn.rollback()
} finally {
JdbcUtils.close(conn);
}
**声明示事务**
利用切面类DataSourceTranscationManager
前置通知: doBegin() 后置通知:doCommit() 异常通知:doRollback()
1配置DataSourceTransactionManager的bean id是transactionManager的标签 配置dataSource property ref是跟jdbcTemplate同一个dataSouce
2配置启用spring的事务注解<tx:annotation-driven />的标签 transaction-Manager跟一中的id连接起来
3在Service方法中添加@Transactional注解 就可以完成事务的功能
@Transactional注解的属性值:noRollbackFor={异常类1.class,异常类2.class} 表示接收到这些异常后不会进行回滚
noRollbackForClassName= "异常类的全类名"
spring默认回滚的是运行时异常RuntimeException及其子异常 rollbackFor=FileNotFoundException.class 表示FileNotFoundException也会回滚,也可以用rollbackForClassName
**事务Transactional的属性**
@Transactional注解 有属性:
readOnly = true :表示只支持查询操作 不支持写操作
timeout :表示操作不可以超过多少秒
propagation:Propagation.xxxx 标志事务的传播特性
**事务的传播特性**
描述的是一个事务方法调用另外一个事务方法的时候,也就是一个service调用另外一个service 必须要指定事务应该如何传播,事务的传播行为可以由传播属性决定,spring有7种传播行为:
用一个例子解释一下上面的内容:
我们所用的例子就是三个事务 1个总的A事务里面执行两个并列的事务B和C
(1)ABC都是REQUIRED: 任何一个地方出现异常所有操作都会全部rollback
(2)ABC都是REQUIREDS_NEW: 异常之后的所有未提交的事务都会失败
(3)A是REQUIRED BC是REQUIREDS_NEW:异常之后的所有未提交的事务都会失败
(4)AB是REQUIRED C是REQUIREDS_NEW:从异常出现的位置开始算起,前面提交的事务成功 没提交的就是失败
(5)AC是REQUIRED B是REQUIREDS_NEW:从异常出现的位置开始算起,前面提交的事务成功 没提交的就是失败
**
xml方式的事务
**
1配置事务特性:
<!-- 事物特性 -->
<tx:advice id="tx_advice" transaction-manager="transactionManager"> 关联事务管理器
<!-- 配置事务特性 -->
<tx:attributes>
<tx:method name="A" propagation="REQUIRED"/>
<tx:method name="B" propagation="REQUIRES_NEW" />
<tx:method name="C" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/> 表示其他的事务是只读的
</tx:attributes>
</tx:advice>
<!-- 配置aop代理 -->
<aop:config>
<aop:advisor advice-ref="tx_advice" pointcut="execution(* com.aaa.service.*Service.*(..))" />
</aop:config>
**
Spring整合web
**
首先介绍一个不推荐的方法:
在servlet中直接使用classpathxmlApplicationContext获取spring容器再获取事务对象
官方推荐的方法:
(1)web.xml中配置一个监听器contextloaderlistener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:你的spring容器</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(2)
在servlet中使用如下方式获取spring容器对象~
方法一(推荐):
WebApplicationContextUtils.getWebApplicationContext(getServletContext())
方法二(不推荐):
getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);