一、spring概述
1、什么是spring
spring是一个以ioc(控制反转)和aop(面向切面编程)为核心的框架。(一个容器,用以容纳对象的容器,包括mybatis.springmvc.等等)
控制反转:简单来说就是让创建对象的任务转移给了spring这个容器。将创建对象和实现功能解耦合了。
面向切面编程:利用注解的方式在不改变原来代码的情况下新增加新的功能。寻找到实体的一个切面。
2、spring有什么作用
是一个容器。能够承担创建对象和接纳其他框架的作用。这也是spring能够久经不衰的原因之一。
3、控制反转(IoC)和依赖注入(Di)
①控制反转:简单来说就是让创建对象的任务转移给了spring这个容器。将创建对象和实现功能解耦合了。
②依赖注入:就是程序运行期间,使用IOC容器动态的赋予对象之间的依赖。将对象与对象之间的耦合度降低。即使程序A在运行的过程中需要使用到程序B的对象资源,不需要自己手动的获取B中的资源,ioc容器会自动的将依赖关系注入。
③使用ioc和Di所带来的益处
- 可维护性比较好:可以单独使用单元测试、调试程序和诊断故障
- 每个开发团队的成员只需要关注自己的要实现的业务逻辑。完全不用关心其他人的工作进展
- 可复用性好
- 生成对象的方式转为外置接口,就是把对象生成放在了配置文件中定义。后序添加新的类只需要在配置文件中修改就可以了
4、applicationContext:spring的核心配置文件
一般将spring的配置文件取名为applicationContext.xml
内部一般是用来配置BeanFactory的配置信息等等的。
一个完整的SSM的配置信息如下所示
<?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:util="http://www.springframework.org/schema/util"
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/util
https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--
用于声明配置文件的位置,一使得下面的属性可以连接到有关于数据库的配置信息
-->
<context:property-placeholder location="classpath:此处修改为配置文件所在的位置conf/jdbc.properties"/>
<!--<util:property-path path="classpath:jdbc.properties"/>-->
<!--声明数据源Datasource,作用是连接数据库的-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!--使用set注入给DruidDataSource赋值-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--表示最大的连接数量-->
<property name="maxActive" value="${jdbc.maxHuman}"/>
</bean>
<!--声明的是mybatis中提供的的sqlSessionFactory类,这个类中创建sqlSession的-->
<bean id="SqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--set注入,将阿里数据库的连接池赋值给dataSource-->
<property name="dataSource" ref="myDataSource"/>
<!--
mybatis中主配置文件的位置,用于读取主配置文件
-->
<property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定sqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName"
value="SqlSessionFactory"/>
<!--
指定dao所在的包名。
mapperScannerConfigurer会扫描该包下的所有接口,把
每个接口都执行一次getMapper
方法,得到的每个接口dao对象都放在spring的容器中
dao对象名称是接口名小写
-->
<property name="basePackage" value="com.bjpowernode.dao"/>
</bean>
<!--声明service的注解@Service所在的包名的位置-->
<context:component-scan base-package="com.bjpowernode.service" />
<!--事务的配置:注解的配置,aspectj的配置-->
<!--<bean name="StudentService"-->
<!--class="com.bjpowernode.service.impl.StudentServiceImpl">-->
<!--<property name="studentDao" ref="studentDao"/>-->
<!--</bean>-->
</beans>
二、Spring中的Bean
1、Bean的配置
在spring的xml文件中配置有关Bean的相关信息:一般都是在application.xml中配置相关的属性。
配置位置:在<Beans><Bean>在此处配置</Bean></Beans>
举例如下:
<!--<bean name="StudentService"-->
<!--class="com.bjpowernode.service.impl.StudentServiceImpl">-->
<!--<property name="studentDao" ref="studentDao"/>-->
<!--</bean>-->
在中大型项目中,都是使用注解的方式来声明bean的目录。
小型项目使用bean标签的方式声明完全没有问题。但是在大型项目中使用bean的方式就显得代码过于冗余。可以选择使用以下的方式
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定sqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName"
value="SqlSessionFactory"/>
<!--
指定dao所在的包名。
mapperScannerConfigurer会扫描该包下的所有接口,把
每个接口都执行一次getMapper
方法,得到的每个接口dao对象都放在spring的容器中
dao对象名称是接口名小写
-->
<property name="basePackage" value="com.bjpowernode.dao" />
</bean>
2、bean的作用域
bean中有一个属性:scope是定义bean声明的对象的生成方式的。总共有七种模式,这里只介绍了最常见的两种
默认为singleton(单例模式),即在bean标签声明之后,无论方位几次这个标签都只有一个地址
第二种常见的模式为:prototype,即每一次访问bean都会重新生成一个对象
3、spring的常用注解
- @Component
可以让使用者不用再书写bean的标签,在类的上面使用该注解相当于子applicationContext.xml中书写了bean的声明。 - @Repository
用于访问数据层(Dao),功能基本与Component相同 - @Service:通常使用于service层
- @Controller:用于controller层
- @Resource和@Autowired:可以理解为在一个类中属性需要调用其他的对象,在属性上面使用
三、Spring AOP
1、什么是AOP
AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充。是一种通过动态代理实现程序功能扩展和统一维护的一种技术。
2、AOP术语
1)横切关注点
从每个方法中抽取出来的同一类非核心业务。
2)切面(Aspect)
封装横切关注点信息的类,每个关注点体现为一个通知方法。
3)通知(Advice)
切面必须要完成的各个具体工作
4)目标(Target)
被通知的对象
5)代理(Proxy)
向目标对象应用通知之后创建的代理对象
6)连接点(Joinpoint)
横切关注点在程序代码中的具体位置
7)切入点(pointcut)
定位连接点的方式。每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物。如果把连接点看作数据库中的记录,那么切入点就是查询条件——AOP可以通过切入点定位到特定的连接点。切点通过org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。
3、最流行的AOP实现-----aspectj
简介
Java社区里最完整最流行的AOP框架。
在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置的AOP。
@Aspect注解
在Spring中声明切面使用@Aspect注解,而且切面也需要交给IOC容器管理,即切面上也需要添加@Component注解。
当在Spring IOC容器中初始化AspectJ切面之后,Spring IOC容器就会为那些与 AspectJ切面相匹配的bean创建代理。
在AspectJ注解中,切面只是一个带有@Aspect注解的Java类,它往往要包含很多通知,通知是标注有某种注解的简单的Java方法。
AspectJ支持5种类型的通知注解:
①@Before:前置通知,在方法执行之前执行
②@After:后置通知,在方法执行之后执行
③@AfterRunning:返回通知,在方法返回结果之后执行
④@AfterThrowing:异常通知,在方法抛出异常之后执行
⑤@Around:环绕通知,围绕着方法执行,相当于动态代理的全过程
**AOP的使用步骤**
1)在Spring核心包的基础上添加以下jar包
spring-aspects-5.3.1.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
2)创建Spring的配置文件,配置自动扫描的包和AspectJ注解支持
<!--配置自动扫描的包-->
<context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>
<!--开启AspectJ注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
3)创建一个类作为切面
a)在类上添加@Aspect注解将该类标识为切面
b)在类上添加@Component注解将该类交给IOC容器管理
4)在切面中添加通知方法
package com.atguigu.spring.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LoggingAspect {
//前置通知,在方法执行之前执行
@Before(value = "execution(public int com.atguigu.spring.aop.Calculator.*(int , int ))")
public void beforeAdvice() {
System.out.println("在方法执行之前执行!");
}
}
5)测试
package com.atguigu.spring.test;
import com.atguigu.spring.aop.Calculator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-aop.xml");
/*
测试AOP
*/
@Test
public void testAOP(){
Calculator calculator = (Calculator) ioc.getBean("calculator");
calculator.add(10,2);
calculator.sub(10,2);
calculator.mul(10,2);
calculator.div(10,2);
}
}
测试结果:在add、sub、mul、div方法执行之前执行切面中的beforeAdvice方法
四、spring的数据库开发
有关于数据库的配置文件
<?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:util="http://www.springframework.org/schema/util"
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/util
https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--
用于声明配置文件的位置,一使得下面的属性可以连接到有关于数据库的配置信息
-->
<context:property-placeholder location="classpath:此处修改为配置文件所在的位置conf/jdbc.properties"/>
<!--<util:property-path path="classpath:jdbc.properties"/>-->
<!--声明数据源Datasource,作用是连接数据库的-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!--使用set注入给DruidDataSource赋值-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--表示最大的连接数量-->
<property name="maxActive" value="${jdbc.maxHuman}"/>
</bean>
<!--声明的是mybatis中提供的的sqlSessionFactory类,这个类中创建sqlSession的-->
<bean id="SqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<!--set注入,将阿里数据库的连接池赋值给dataSource-->
<property name="dataSource" ref="myDataSource"/>
<!--
mybatis中主配置文件的位置,用于读取主配置文件
-->
<property name="configLocation" value="classpath:conf/mybatis.xml"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定sqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName"
value="SqlSessionFactory"/>
<!--
指定dao所在的包名。
mapperScannerConfigurer会扫描该包下的所有接口,把
每个接口都执行一次getMapper
方法,得到的每个接口dao对象都放在spring的容器中
dao对象名称是接口名小写
-->
<property name="basePackage" value="com.bjpowernode.dao"/>
</bean>
<!--声明service的注解@Service所在的包名的位置-->
<context:component-scan base-package="com.bjpowernode.service" />
<!--事务的配置:注解的配置,aspectj的配置-->
<!--<bean name="StudentService"-->
<!--class="com.bjpowernode.service.impl.StudentServiceImpl">-->
<!--<property name="studentDao" ref="studentDao"/>-->
<!--</bean>-->
</beans>
操作数据库
1)增删改
JdbcTemplate.update(String, Object…)
public class JdbcTemplateTest {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans-jdbc.xml");
JdbcTemplate jdbcTemplate = (JdbcTemplate) ioc.getBean("jdbcTemplate");
/*
测试增删改
*/
@Test
public void testUpdate(){
//写sql语句
String sql = "insert into employee(last_name,email,salary) values(?,?,?)";
//调用JdbcTemplate中的update方法
jdbcTemplate.update(sql,"雷军","leijun@xiaomi.xom",9999.00);
}
}
2)批量增删改
JdbcTemplate.batchUpdate(String, List<Object[]>)
Object[]封装了SQL语句每一次执行时所需要的参数
List集合封装了SQL语句多次执行时的所有参数
/*
测试批量增删改
*/
@Test
public void testBatchUpdate(){
//写sql语句
String sql = “insert into employee(last_name,email,salary) values(?,?,?)”;
//创建一个List
List<Object[]> batchArgs = new ArrayList<>();
Object[] arg1 = new Object[]{“李彦宏”,“liyanhong@baidu.com”,8888.00};
Object[] arg2 = new Object[]{“刘强东”,“liuqiangdong@jd.com”,7777.00};
Object[] arg3 = new Object[]{“张一鸣”,“zhangyiming@douyin.com”,6666.00};
batchArgs.add(arg1);
batchArgs.add(arg2);
batchArgs.add(arg3);
//调用JdbcTemplate中的批处理方法
jdbcTemplate.batchUpdate(sql,batchArgs);
}
3)查询单一值
JdbcTemplate.queryForObject(String, Class, Object…)
/*
测试获取一个单一值
*/
@Test
public void testGetSingonValue(){
//写sql语句
String sql = “select avg(salary) from employee”;
//调用JdbcTemplate中的queryForObject方法
Double avgSalary = jdbcTemplate.queryForObject(sql, Double.class);
System.out.println(avgSalary);
}