目录
一.为什么要学spring?
1.简化开发
Spring是一个十分优秀的框架,它的目的是为了简化企业级Java的开发。使用过Servlet开发网站的都清楚,Servlet包含了大量重复性的代码,我们需要花大量的时间去重复写,而Spring可以避免这种重复的操作;
2.大势所趋
市面上几乎所有公司都在用这门技术,为了以后的就业需求,我们必须掌握
3.后续学习
在之后学习的SpringMVC、SpringBoot、SpringCould等流行技术,都是以Spring为基础的,没有Spring作为基础,无法掌握高层次的技术。
二、Spring的特点
在学习一门技术之前,除了了解他的用途之外,也需要了解它的一些优缺点,以便在以后的开发中扬长避短。
Spring的用途就是用来解决企业级应用开发的复杂性
优点:
1、开源、免费的框架(容器)
2、轻量级、非入侵式的框架
3、控制反转(IOC)、面向切面编程(AOP)
4、支持事物处理、对框架整合
总结:Spring就是一个轻量级的控制反转(IOC)、面向切面编程(AOP)的框架。
三、IOC(控制反转)
控制反转是一种设计思想,主要作用是用来减少类和类之间的耦合度
IOC容器持有了创造、查找依赖对象的控制权,由容器来进行注入组合对象,从而达到松散耦合的目的;
DI(依赖注入)是实现IOC的一种方式
依赖:类依赖于容器
注入:IOC注入某个对象,注入了所需的外部资源(对象、资源、常量)
本质上来说,IOC和DI是不同维度的同一种表现,也以理解为:IOC为Bean的注册,DI为Bean的初始化
四、DI(依赖注入)方式(常用)
- 构造器注入
<bean id="person01" class="com.xawl.wsf.Person" > <!--下标注入--> <constructor-arg index="0" value="李四"></constructor-arg> <constructor-arg index="1" value="18"></constructor-arg> </bean> <bean id="people02" class="com.chai.lesson2.Person"> <!--类型注入--> <constructor-arg type="String" value="王五"></constructor-arg> <constructor-arg type="int" value="19"></constructor-arg> </bean> <bean id="people03" class="com.chai.lesson2.Person"> <!--参数名注入--> <constructor-arg name="name" value="王五"></constructor-arg> <constructor-arg name="age" value="19"></constructor-arg> </bean>
- Set注入
<bean id="hello" class="com.xawl.wsf.HelloSpring"> <!-- name的值与set方法setName对应,若无,无法运行 --> <property name="name" value="张三"></property> </bean>
- 其他注入
<!-- p标签注入:--> <!-- c标签注入:--> <!-- 配置文件--> <?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:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="people_p" class="com.xawl.day02.pojo.People" p:age="12" p:name="李四"/> <bean id="people_c" class="com.xawl.day02.pojo.People" c:age="21" c:name="张三"/>
五、Spring配置
- 别名配置 alias
<!-- 别名alias --> <alias name="people" alias="p1"/> <!-- name别名设置,支持多别名 ---> <bean id="people" class="com.xawl.day02.pojo.People" name="p1,p2,p3"/>
- xml文件整合
<!-- 多个xml 文件合并为一个--> <beans> <import resource="ioc.xml"/> <import resource="bean.xml"/> </beans>
- 作用域
<beans> <!-- 原型模式,每次getbean取出的为不同对象--> <bean id="people01" class="com.xawl.day02.pojo.People" scope="prototype"> <!-- 单例模式,每次getbean取出的为同一对象--> <bean id="people02" class="com.xawl.day02.pojo.People" scope="singleton"> </beans>
//原型模式构建bean测试 public class Testt { public static void main(String[] args) { ApplicationContext ioc = new ClassPathXmlApplicationContext("day02.xml"); People p1 = ioc.getBean("people01", People.class); People p2 = ioc.getBean("people01", People.class); System.out.println("原型测试:"+(p1==p2)); } } //输出结果:原型测试:false //单例模式构建bean测试 public class Testt { public static void main(String[] args) { ApplicationContext ioc = new ClassPathXmlApplicationContext("day02.xml"); People p1 = ioc.getBean("people02", People.class); People p2 = ioc.getBean("people02", People.class); System.out.println("单例测试:"+(p1==p2)); } } //输出结果:单例测试:true
六、自动装配
首先说一下什么是装配:依赖注入的本质就是装配,装配是依赖注入的具体行为
装配的方式:
1.XML显示装配
2.Java显示装配
3.隐式装配
两种显示装配的方式,在之前已经了解,自动装配基于的就是隐式装配,根据给定的条件,查找符合条件(名称、类型)的数据,进行装配。
1.根据名称自动装配
条件:自动注入bean的id名称必须和Set方法的名称关联,且唯一,否则装配失败
实体类:
public class User {
private String name;
private int age;
private String sex;
private Dog dog;//自动装配目标
private Cat cat;//自动装配目标
}
配置文件:
<!--根据名称自动装配-->
<bean id="user" class="com.xawl.auto.pojo.User" autowire="byName"/>
<!--自动装配目标-->
<bean id="dog" class="com.xawl.auto.pojo.Dog" >
<property name="sing" value="汪汪"></property>
<property name="dogName" value="狗狗"></property>
</bean>
<!--自动装配目标-->
<bean id="cat" class="com.xawl.auto.pojo.Cat" >
<property name="sing" value="喵喵喵"></property>
<property name="carName" value="喵"></property>
</bean>
2.根据类型自动装配
条件:此类型全局唯一,否则装配失败
<!--根据名称自动装配-->
<bean id="user" class="com.xawl.auto.pojo.User" autowire="byType"/>
七、注解开发
开发前提:
①导入约束
<?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">
</beans>
②开启注解支持
<!-- 开启注解支持-->
<context:annotation-config/>
③对于定义注册bean类注解,需要进行包扫描
<context:component-scan base-package="com.xawl.annotation.pojo"/>
注解分类:
①注册bean
@Component:组件,放于类上 (等价于:<bean id="类首字母小写" class="本类">)
②衍生的注册bean
MVC三层架构
Dao层 -----------------@Repository
service层 -------------@Service
controller层 -----------@Controller
其他层------------------@Component
这四个注解功能一样,用于注册,分层不同
③属性注入注解
@Value("XXX")放于set方法、变量上 (等价于<property name="本属性" vlaue="XXX">)
④作用域注解
@Scope("singleton")/prototype 放于类上 单例作用域/原型作用域
⑤自动装配注解
@Autowired
自动装配,先通过类型查找,再通过名字,都没找到注入失败;找到多个运行失败
@Qualifier(value="××")
指定名称式自动装配,value=目标装配的id,需要保证类型一致
@Resource @Resource(name = "××")
功能和以上两个注解结合起来一样,先通过类型查找,再通过名称,名称可指定
总结:
xml:更万能,适用于任何场合,维护方便
注解:不是自己的类使用不了,维护复杂
使用:xml:管理Bean 注解:属性的注入
八、脱离XML配置Spring
也就是用通过注解使java类替代xml文件的功能
1.注册类:@Configuration 也会被注册,代表这是配置类
2.扫描包:@componentScan("")扫描包
3. @Import:多合一,引入其他的配置类 等价于<import>
4.@bean 相当于bean标签
5.方法名,返回值 方法名:id属性 返回值:class属性
通过AnnotationConfig来获取
//注册类标志,表示此类为配置类
@Configuration
//引入别的配置类
@Import(SpringConfig01.class)
//扫描包
@ComponentScan("com.xawl.annotation.pojo")
public class SpringConfig {
//bean标签
@Bean
//id="people01" class="....People"
public People people01(){
return new People();
}
}
测试类:
@Test
public void test01(){
ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfig.class);
People bean = (People)ioc.getBean("people01");
System.out.println(bean);
}
九、AOP
AOP底层层理:动态代理模式(基于反射)
代理模式:
1.静态代理模式:
①.角色分析:
抽象角色:接口、抽象类实现
真实角色:被代理的角色(房东)
代理角色:代理真实角色(代理)+附属操作
客户:访问代理的人(租房的人)
②.优点:
使角色操作更纯粹,不需要设计公共的业务
公共业务交给代理角色,单一职责原则
公共业务发生扩展时,方便管理
③.缺点
一个角色产生一个代理,代码量翻倍
2.动态代理模式
与静态代理区别:使用反射机制动态生成代理类
Proxy 用于生产动态代理的实例
InvocationHandler 用于调用处理程序并返回结果
结合了静态代理的所有优点
动态代理代理接口,一般针对一类业务
一个动态代理可以代理多个类,只要实现了同一接口
AOP详解:面向切面编程
需求:在程序运行期间,需要增加日志等功能,若在程序中直接修改,是不符合开闭原则的。在不修改原有代码的情况下,并结合代理模式,AOP诞生了
面向切面:在程序运行时,动态的将代码切入到指定的类中指定的方法、指定的位置的编程,就是面向切面编程
实现:
1.导包
maven下导入
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
2.引入约束
<?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">
</beans>
3.三种实现方式
①API接口实现
定义通知类,继承API接口
API接口: 前置通知:MethodBeforeAdvice 后置通知:AfterAdvice 返回通知:AfterReturningAdvice 异常通知:ThrowsAdvice
//前置通知
public class AfterLog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("方法调用前,调用了"+method.getName()+"方法");
}
}
//返回通知
public class BeforeLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("返回通知:返回值:"+returnValue+"method:"+method.getName());
}
}
配置XML文件
<!--注册Bean-->
<bean id="sql" class="com.xawl.wsf.aop.SqlImpl"/>
<bean id="before" class="com.xawl.wsf.aop.BeforeLog"/>
<bean id="after" class="com.xawl.wsf.aop.AfterLog"/>
<!-- 定义切入点-->
<aop:config>
<!--定义切入点表达式-->
<aop:pointcut id="notice" expression="execution(* com.xawl.wsf.aop.SqlImpl.*(..))"/>
<!--执行环绕增强-->
<aop:advisor advice-ref="before" pointcut-ref="notice"/>
<aop:advisor advice-ref="after" pointcut-ref="notice"/>
</aop:config>
测试:
@Test
public void test() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("ioc.xml");
Sql sql = (Sql) ioc.getBean("sql");
sql.insert();
}
②切面类实现
定义切面类
//切面类
public class Notice {
public void befor(){
System.out.println("方法运行前");
}
public void after(){
System.out.println("方法运行后");
}
public void returning(){
System.out.println("返回通知");
}
}
配置xml
<!-- 注册实体类 -->
<bean id="sql" class="com.xawl.wsf.aop.SqlImpl"/>
<bean id="ice" class="com.xawl.wsf.aop.Notice"/>
<aop:config>
<!--引入切面类-->
<aop:aspect ref="ice">
<!--定义切入点表达式-->
<aop:pointcut id="notice" expression="execution( * com.xawl.wsf.aop.SqlImpl.*(..))"/>
<!--增强环绕通知,绑定切面类的方法-->
<aop:before method="befor" pointcut-ref="notice"/>
<aop:after method="after" pointcut-ref="notice"/>
<aop:after-returning method="returning" pointcut-ref="notice"/>
</aop:aspect>
</aop:config>
③注解实现
配置文件
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
<!--注册bean-->
<bean id="sql" class="com.xawl.wsf.aop.SqlImpl"/>
<bean class="com.xawl.wsf.aop.NotIceZj"/>
注解实体类
//注解方式实现
//标记为切切面类
@Aspect
public class NotIceZj {
//前置通知
@Before("execution(* com.xawl.wsf.aop.SqlImpl.*(..))")
public void befor(){
System.out.println("+注解++运行前");
}
//后置通知
@After("execution(* com.xawl.wsf.aop.SqlImpl.*(..))")
public void after(){
System.out.println("注解方法运行后");
}
//返回通知
@AfterReturning("execution(* com.xawl.wsf.aop.SqlImpl.*(..))")
public void returning(){
System.out.println("返回通知");
}
//环绕通知
@Around("execution(* com.xawl.wsf.aop.SqlImpl.*(..))")
public void around(ProceedingJoinPoint pr) throws Throwable {
System.out.println("环绕前");
//执行方法
Object proceed = pr.proceed();
System.out.println("环绕后");
}
}
十、整合Mybatis
Mybatis与spring整合,使用spring容器管理对象
步骤:
1.导包
需要的包:junt、mybatis、mysql、spring、aop、mybatis-spring
<!--数据库包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--spring支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!--用于spring操作数据库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!--aop-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
2.编写XML配置文件
(1)mybatis-config.xml 主要用于配置别名、set设置(可被spring全完取代)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- set设置 -->
<settings>
<setting name="" value=""/>
</settings>
<!-- 别名 -->
<typeAliases>
<package name="com.xawl.affair.pojo"/>
</typeAliases>
</configuration>
(2)spring-mybatis.xml
主要作用是配置数据源、获取SqlSessionFactory对象、获取SqlSession对象
<?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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--1.DataSource 获取数据源,配置连接数据库的信息-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&userUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--2.获取SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--传入dataSource值-->
<property name="dataSource" ref="dataSource"/>
<!--绑定Mybatis配置文件,两个相辅相成-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--mapper绑定xml,绑定所有,一劳永逸-->
<property name="mapperLocations" value="classpath:com/xawl/affair/dao/*.xml"/>
</bean>
<!--3. 获取SqlSessionTemplate 与SQLSession相同-->
<bean name="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
(3)applicationContext.xml
用于融合其他XML,并用来配置注册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"
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">
<!--导入其他xml-->
<import resource="spring-mybatis.xml"/>
<!--扫描包-->
<context:component-scan base-package="com.xawl.affair.dao"/>
<!-- 注解开启后,可省略 -->
<!-- <bean id="userMapper" class="com.xawl.affair.dao.UserMapperImpl" >-->
<!-- <property name="sqlSession" ref="sqlSession"/>-->
<!-- </bean>-->
</beans>
3.XML语句、增删改查
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--绑定一个mapper接口-->
<mapper namespace="com.xawl.affair.dao.UserMapper">
</mapper>
4.Mapper接口文件(dao层,与Mybatis一致)
5.书写Mapper实现类
(1)set方法注入SqlsessionTemplate
//set方法注入
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
(2)继承SqlSessionDaoSupport类,此类中封装了SqlsessionTemplate的构造器、set方法,可直接使用其getSession()方法获得SqlsessionTemplate对象
public class CourseMapperImpl extends SqlSessionDaoSupport implements CourseMapper{
//继承SqlSessionDaoSupport类,此类内置了构造、set方法,可直接使用set方法获得
public List<Course> getcourse() {
//getSqlSession()方法获取对象
CourseMapper mapper = getSqlSession().getMapper(CourseMapper.class);
return mapper.getcourse();
}
}
此时,XML只需给其父类注入SqlSessionFactory对象即可
<!--使用继承SqlSessionDaoSupport方法,给其父类直接注入sqlSessionFactory即可-->
<bean id="courseMapper" class="com.xawl.spring.dao.CourseMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
6.测试,通过spring容器获取结果
@Test
public void test01(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = ioc.getBean("userMapper", UserMapper.class);
List<User> list = userMapper.getall();
for (User user : list) {
System.out.println(user);
}
}
十一、Spring声明式事务
事务:
要么都成功,要么都失败,要求:完整性,一致性
ACID原则:
原子性:一个事务是一个整体,不可分割,对其操作要么都做,要么都不做
一致性:数据库事务是从一个一致性状态变成另一个一致性状态
隔离性:并发时,防止数据损坏
持久性 :事务提交后,结果不可被影响
声明式事务:
结合AOP,在符合OCP原则的基础上,加入事务
1.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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
</beans>
2.XML配置
原理:AOP
可以指定任意包、任意类、任意方法加入事务
<!-- 1.添加对象 -->
<bean id="manager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!-- 2.导入引用文件——tx 配置事务通知 -->
<tx:advice id="interceptor" transaction-manager="manager">
<tx:attributes>
<!-- 给哪些方法配置事务-->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置事务切入-->
<aop:config>
<aop:pointcut id="peiont" expression="execution(* com.xawl.affair.dao.*.*(..))"/>
<aop:advisor advice-ref="interceptor" pointcut-ref="peiont"/>
</aop:config>
3.测试
必须是在同一方法中开启事务,触发异常时进行回滚
@Override
public int setage(Map<Object, Object> map) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.setage(map);
}
public int setageall(Map<Object, Object> map1,Map<Object, Object> map2){
int set1 = setage(map1);
int set2 = setage(map2);
if(set1+set2<2){
throw new RuntimeException("失败");
}
return set1+set2;
}
总结:spring主要核心思想IOC、AOP,一个降低耦合性,一个面向切面开发,熟练掌握其思想,并熟悉注解的使用,为下一步打下基础。