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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
在其中配置bean
<bean id="accountdao" class="com.zhonghuan.Dao.impl.AccountDaoimpl"></bean>
</beans>
ApplicationContext的三个实现类
类创建的时机
ApplicationContext:在构建核心容器时,创建对象的策略的方式是立即创建的方式,读取完配置文件立即创建对象
BanFactory:创建对象的策略是延时加载,在通过id获取对象的时候才创建对象
Spring中的依赖注入
IOC的作用是降低程序间的耦合(依赖关系),依赖关系的管理都可以交给Spring,在当前类需要使用其它类的对象,由spring向我们提供,我们只需要在配置文件中说明,依赖关系的维护就称之为依赖注入
能注入的数据共三类
1.基本类型的数据和String
2.其他bean类型:在配置文件中或注释中配置过的bean
2.复杂类型和集合类型
基本数据类型:
java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
byte,short,int,long,double,float,char,Boolean,
<!--把对象的创建交给spring来管理-->
<!--spring对bean的管理细节
1.创建bean的三种方式
2.bean对象的作用范围
3.bean对象的生命周期
-->
<!--创建Bean的三种方式 -->
<!-- 第一种方式:使用默认构造函数创建。
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
-->
<!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
-->
<!-- 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean>
-->
<!-- bean的作用范围调整
bean标签的scope属性:
作用:用于指定bean的作用范围
取值: 常用的就是单例的和多例的
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="prototype"></bean>
-->
<!-- bean对象的生命周期
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着。
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
-->
使用注解配置
使用注解和使用xml文件配置所用的xml文件约束不同
在使用注解之前,需要告知spring在创建容器时要扫描的包,
配置所需要的标签不是在beans的约束中,而是一个名称为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
http://www.springframework.org/schema/context/spring-context.xsd">
<!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为
context名称空间和约束中-->
<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>
根据作用类型注解分类
用于创建对象的:
1.@Component:
作用:把当前对象存储到容器中,
@Component(value = "accountservice")注解id默认值为类名首字母小写,
也可以通过value来更改,仅有一个value时可省略
下面三个注解与Component作用相同,是spring为了使三层架构更佳清晰
2.@Controller:用在表现层
3.@Service:用在业务逻辑层
4.@Repository:用在持久层
用于注入数据的
他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
1.Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
2.Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
属性:
value:用于指定注入bean的id。
3.Resource
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
@Autowired
private AccountDao accountdao2;
权限修饰符 类名 对象名
当使用@AutoWrite注解按照类型自动注入时,首先会按照类名去map类型的Spring容器中寻找map中的value进行自动匹配,如果找到唯一匹配就自动注入,如果找到多个匹配结果就再将对象名与Spring Map容器的key进行匹配。
在使用注解将对象配置进Spring容器时,key为id,
value为public class AccountServiceimpl implements AccountService格式
用于注入数据的
他们的作用就和在xml配置文件中的bean标签中写一个 <property>标签的作用是一样的
Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean 对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注入的变量类 型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
属性:
value:用于指定注入bean的id。
Resource
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
用于改变作用范围的
他们的作用就和在bean标签中使用scope属性实现的功能是一样的
Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值:singleton prototype
和生命周期相关 (了解)
他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
通过配置类替换掉xml文件,完全使用注解配置
ApplicationContext ac=new AnnotationConfigApplicationContext(config.class);
获得容器对象,传入一个由@Configuration注解配置过的类的字节码
@Configuration表示此类是一个配置类
@@ComponentScan(basePackages = "com.itheima")表示要扫描的包 其中basePackages可以省略,也可以用value替代
@Bean(name=“”)将对象存入Spring容器中,key为name中的名称
@Scope("prototype")设置对象为多例对象
实际开发中应遵循怎么方便怎么配置,一般来说自己写的类使用注解配置,jar包中的类使用xml文件配置
当@Qualifier作为方法参数的注解时,可以不依靠@AutoWride独立存在
public QueryRunner Createrunner(@Qualifier("ds1") DataSource dataSource ){
return new QueryRunner(dataSource);
}
spring整合junit
1.导入Spring-test坐标
2.@Runwith注解将junit中的main方法替换成spring中的main方法
@RunWith(SpringJUnit4ClassRunner.class)
3.告知spring运行器spring和ioc创建是基于注解还是xml的,并提供位置
xml文件创配置:locations
@ContextConfiguration(locations=“classpath:bean.xml”)
classes:指定配置类所在位置
@ContextConfiguration(classes = config.class)
4.使用的spring版本在5.0以上的话要求junit版本在4.1.2上,不然会报错
spring中基于XML的AOP配置步骤
1、把通知Bean也交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!--spring中基于XML的AOP配置步骤
1、把通知Bean也交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
-->
<!-- 配置Logger类 -->
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before>
</aop:aspect>
</aop:config>
</beans>
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
通用化切入点表达式
<aop:pointcut id="ser"
expression="execution(* com.itheima.service.impl.*.*(..))"> </aop:pointcut>
写在<<aop:aspect>标签前:
作为公共的,所有<aop:aspect>标签都可以引用
写在<aop:aspect>标签内:
只能在此标签内部使用
spring环绕通知
问题:
在xml文件中配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
分析:
代码中没有明确的切入点方法调用。
解决:
Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
spring中的环绕通知: 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
public Object aroundPringLog(ProceedingJoinPoint pjp){ //返回Object类型的切入点方法的返回值
Object returnValue = null; //定义业务层方法(切入点方法)执行后的返回值
try{
Object[] args = pjp.getArgs(); //获取业务层方法(切入点方法)的参数
System.out.println("Logger类中的前置方法执行了");
returnValue = pjp.proceed(args);//调用业务层方法(切入点方法)并传入参数
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return returnValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
使用注解配置aop
xml文件中
//配置扫描注解
<context:component-scan base-package="com.zhonghuan"></context:component-scan>
//配置开启注解aop
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
切面类中
//将此类存入核心容器中
@Component("logger")
//表示当前类是一个切面类
@Aspect
//新建一个方法用于配置通用化切入点表达式
@Pointcut("execution(* com.zhonghuan.Service.impl.AccountServiceimpl.*(..) )")
public void pc1(){}
//前置方法
@Before("pc1()")
//后置方法
@AfterReturning("pc1()")
//异常方法
@AfterThrowing("pc1()")
//最终方法
@After("pc1()")
//配置环绕方法
@Around("pc1()")
由于单独配置四个方法时,spring在方法调用顺序上先调用后置方法/异常方法 后调用最终方法,所以建议要么使用xml文件配置四个方法,要么使用注解配置环绕方法
切面类案例
package com.zhonghuan.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//将类存入spring容器
@Component("logger")
//表示类是个切面类
@Aspect
public class logger {
// 配置通用切入点
@Pointcut("execution(* com.zhonghuan.Service.impl.AccountServiceimpl.*(..) )")
public void pc1(){
}
//前置方法
@Before("pc1()")
public void beforeprint(){
System.out.println("日记记录开始");
}
//最终方法
@After("pc1()")
public void afterprint(){
System.out.println("日志记录结束");
}
//配置异常方法
@AfterThrowing("pc1()")
public void exceptionprint(){
System.out.println("异常方法");
}
//配置后置方法
@AfterReturning
public void commitprint(){
System.out.println("提交方法开始");
}
//配置环绕方法
@Around("pc1()")
public Object aroundprintlog(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs(); //获取业务层方法(切入点方法)的参数
Object returnvalue=null; //定义业务层方法(切入点方法)执行后的返回值
try {
System.out.println("前置方法被执行");
returnvalue = pjp.proceed(args);
System.out.println("后置方法被执行");
return returnvalue;
} catch (Throwable throwable) {
System.out.println("异常方法被执行");
throw new RuntimeException(throwable);
}finally {
System.out.println("最终方法被执行");
}
}
}
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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.zhonghuan"></context:component-scan>
<!-- 配置spring开启注解AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
JdbcTemplate:
增删改查
template.update("INSERT into account (name,money) VALUES (?,?)","test",123);
template.update("delete from account where id = ?",5);
template.update("update account set name = ?,money = ? WHERE id = ?","ddd",123,4);
List<Account> query = template.query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), 2);
System.out.println(query);
执行查询操作的时候需要传入一个封装方式,可以使用spring自带的封装方式:
new BeanPropertyRowMapper<Account>
dao编写的两种方式:
1.为了去除掉创建template的重复代码,可以采用继承JdbcDaoSupport类
优点:此类中含有创建JdbcTemplate对象的方法,
可以直接通过super.getJdbcTemplate()方法获取并使用对象
缺点:由于继承后JdbcTemplate对象由父类提供,所以只能使用xml文件配置
2.自己创建JdbcTemplate,
优点:可以使用AutoWrite注解配置
缺点:需要自己写JdbcTemplate
通过继承获取template时,
super.getJdbcTemplate().query()进行查询,
在xml文件中配置dao时需要传入template或者dataSource
public class AccountDaoimpl extends JdbcDaoSupport implements AccountDao {
public Account findAccountByid(int id) {
List<Account> accounts = super.getJdbcTemplate().query("select * from account where id = ?", new BeanPropertyRowMapper<Account>(Account.class), 2);
return accounts.get(0);
}
配置dao
<bean id="accountdao" class="com.zhonghuan.dao.impl.AccountDaoimpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
事务的隔离级别:四种
事务的传播行为:定义什么时候有事务什么时候没有
必须有:增删改等对数据库进行更改
REQUIRED(默认值):如果当前有事务就用,没有就新建
可有可无:查询
SUPPORTS:如果当前有就使用,如果没有就不用
事务超时时间:默认值-1,表示没有限制,如果设置以秒为单位
通过spring提供的api配置事务
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置业务层-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置账户的持久层-->
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
<property name="username" value="root"></property>
<property name="password" value="1234"></property>
</bean>
<!-- spring中基于XML的声明式事务控制配置步骤
1、配置事务管理器
2、配置事务的通知
此时我们需要导入事务的约束 tx名称空间和约束,同时也需要aop的
使用tx:advice标签配置事务通知
属性:
id:给事务通知起一个唯一标识
transaction-manager:给事务通知提供一个事务管理器引用
3、配置AOP中的通用切入点表达式
4、建立事务通知和切入点表达式的对应关系
5、配置事务的属性
是在事务的通知tx:advice标签的内部
-->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 配置aop-->
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.itheima.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入点表达式和事务通知的对应关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
</beans>