Spring框架
Spring是一个基于IOC和AOP的结构J2EE系统的框架(容器)
ioc
IOC容器 控制的实现方式 是Spring的基础,Inversion Of Control,是一种设计思想,di依赖注入是实现ioc的一种方式
是一种通过描述(xml或者注解)并通过第三方或获取对象的方式
- ①多态实现 耦合度太高 传统开发 需求发生更改的时候需要修改impl下的东西
public interface UserDao{void getUser()} //UserDao
puclic class UserDaoImpl implements UserDao{
public void getUser(){
System.out.println()
}
}
public interface UserService{void getUser()} //UserService
puclic class UserServiceImpl implements UserService{
UserDao userDao=new UserDaoImpl();
public void getUser(){
UserDao.getUser();
}
}
//用户实际上调用的是dao层
UserService userservice = new UserServiceImpl();
userService.getUser();
-
②创建一个set接口
Service的修改 接口实现降低耦合度
Private UserDao userDao; private void setUserDao(UserDao,userDao){this.userDao = userDao;}
之前程序主动创建对象 控制权在程序员手上
set注入后 程序不在具有主动性 而是变成了被动的接受对象
这是ioc的原型 set方法是spring的底层,
③xml实现
ioc创建对象的方式
- 默认是用无参构造方法
- 有参的方式创建对象
在配置文件加载的时候 容器中管理的对象已经初始化了
-
别名
<alias name="user" alias="userNew"/>
id bean的唯一标识符 class bean对象所对应的全限定名 name也可以取别名
applicationcontext相当于总的配置文件 该文件下import可以导入其他的配置文件 相当于交给spring管理
DI
依赖注入:构造器注入 set注入
<bean id="student" class="com.kuang.pojo.Student">
<!--第一种,普通值注入,value-->
<property name="name" value="樊帅"/>
<!--第二种,Bean注入,ref-->
<property name="address" ref="address"/>
<!--数组-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
<!--List-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>敲代码</value>
<value>看电影</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="111111222222223333"/>
<entry key="银行卡" value="1321231312312313123"/>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="driver">20190525</prop>
<prop key="url">男</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
p c 命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.kuang.pojo.User" p:name="樊帅" p:age="18"/>
<!--c命名空间注入,通过构造器注入:construct-args-->
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="樊帅" scope="prototype"/>
bean的作用域(scope)
singleton prototype request session application websocket
bean的自动装配
- 自动装配是spring满足bean依赖的一种方式
- spring会在上下文中自动寻找 并自动给bean装配属性
在spring中的三种装配方式
1 在xml中显示的配置
2在Java中显示的配置
3 隐式自动装配 bean
Autowired
byName自动装配 会自动在上下文中查找 和自己对象set方法后面的值对应的bean 只能识别名字叫樊帅
byType:会自动在上下文中查找 和自己对象属性类型相同的bean 狗类有两个实例byType不知道该调用哪个
注解方式实现自动装配
导入约束 context约束
配置注解的支持 这句话的意思为开启注解的支持<context:annotation-config/>
对bean进行注解方式
-
@Autowired 表明该类自动装配 该注解下的属性必须于bean实例下的id保持一致
(也可以放在set方法上,有了这个注解就可以省略set方法)
-
@Autowired(require = false) 说明该对象可以为空 否则不允许为空
-
@Qualifier(value="") bean有多个id的情况下 指定装配的值
-
@Resourse (name = “”) 可以执行bean的id 不加name属性bean得唯一
@Autowired
private Dog dog;
bean实例下
<context:annotation-config/>
<bean id="dog" class="com.fan.pojo.Dog"/>
Resourse和autowirse的区别
都是用来自动装配的 都可以放在属性字段上
Autowirse默认使用bytype方式,如果多个类型相同,再通过byname(对象必须存在) Qualifier指定value
resourse默认是通过byname的方式实现,如果找不到名字 则通过bytype实现 指定name
执行顺序不同 Autowirse默认使用bytype方式 resourse默认是通过byname的方式实现
④注解实现
-
@Componment
等价于<bean id="user" class="com.kuang.pojo.User"/>
@Value(“kuansghen”); 放在属性上 显性的给属性注入值 也可以注入在set方法上
public String name;相当于 <property name="name" value="kuangshen"/>
衍生注解 这些都是Componment组件 仅仅是叫法不同 都是代表将类注册到spring容器中 装配bean 交给spring管理
- dao @Repository
- service @service
- controller @ controller
作用域 scope(“prototype”)
-
小结
- xml用来管理bean
- 注解只负责完成属性的注入
- 我们在使用的时候只需要注意开启注解的支持
扩展 使用Java的方式配置springboot javaconfig
aop
静态代理
类似于律师会务所 婚庆公司
角色分析
- 抽象角色 一般会使用抽象类和抽象接口来解决
- 真实角色 被代理的角色
- 代理角色 代理真实角色 代理真实角色后 我们一般会做一些附属操作
- 客户 访问代理对象的人
代码步骤
- 接口 需要干什么service
- 真实角色 ServiceImpl 真实角色和代理角色都实现了service
- 代理角色 声明真实角色(将真实角色注入到代理角色) 代理角色一套流程,只需要将真实角色注入进去 降低了耦合
- 客户端访问代理角色 调用接口方法实现
组合优于继承 一般不用继承 在类中定义一个私有的方法
动态代理
改变了静态代理的缺点
底层为反射
- 动态代理和静态代理角色一样
- 动态代理的代理类是动态生成的 不是我们直接写好的
- 基于接口的动态代理(jdk的动态代理) 基于类的动态代理(chlib)
- javaassist java字节码
需要连接两个类:Proxy invocationHandler(invoke方法)
动态代理的底层实现
动态代理具体步骤:
- 通过实现 InvocationHandler 接口创建自己的调用处理器;
- 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
aop切面编程思路
一个项目的基本核心功能实现,能够跑起来后,需要增加一些辅助功能 横向开发
aop在spring中的作用
aop代码解释
applicationContext.xml
- 方式一 使用原生Spring API接口
配置aop:需要导入aop的约束
<aop:config>
<!--切入点:expression:表达式,execution(要执行的位置! * * * * *) 声明日志切面-->
<aop:pointcut id="pointcut"
expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加!-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
- 方式2 自定义类
声明业务对象
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<!--自定义切面, ref 要引用的类 aop核心业务功能-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point"
expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
- 方式3
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--方式三-->
<bean id="annotationPointCut" class="com.kuang.diy.AnnotationPointCut"/>
<!--开启注解支持! JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true")-->
<aop:aspectj-autoproxy/>
@Aspect 注解表示这是一个切面
@Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))") 环绕
执行顺序
环绕前
signature:void com.kuang.service.UserService.delete()
=====方法执行前======
删除了一个用户
环绕后
null
=====方法执行后======
spring整合mybatis
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个
SqlSessionFactory 和至少一个数据映射器类。
可使用 SqlSessionFactoryBean 来创建 SqlSessionFactory 。
在spring的xml配置文件中配置工厂bean 就是下方的数据源配置
-
1导入相关的包
- junit
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
- mybatis
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency>
- mysql-connector-java
<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.1.9.RELEASE</version> </dependency> <!--Spring操作数据库的话,还需要一个spring-jdbc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.9.RELEASE</version> </dependency>
- aspectJ AOP 织入器
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency>
- mybatis-spring整合包 【重点】
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> lombok <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.10</version> </dependency>
- maven静态资源过滤问题
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
编写配置文件
-
代码实现
配置文件
mybatis-config.xml
<?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核心配置文件-->
<configuration>
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
<!--设置-->
<!--<settings>-->
<!--<setting name="" value=""/>-->
<!--</settings> -->
</configuration>
spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
我们这里使用Spring提供的JDBC : org.springframework.jdbc.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&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--sqlSessionFactory 关联mybatis-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定Mabatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate:就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
//导入了spring的配置文件
<import resource="spring-dao.xml"/>
<!---->
<bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
<bean id="userMapper2" class="com.kuang.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
事务管理
编程式事务管理
-
将事务管理代码嵌到业务方法中来控制事务的提交和回滚
-
缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理
- 一般情况下比编程式事务好用。
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring
xml的配置文件tx
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
jdbc事务(配置声明式事务)
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
配置事务通知以及事务的传播性
<!--结合AOP实现事务的织入-->
<!--配置事务通知;-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给那些方法配置事务-->
<!--配置事务的传播特性:new propagation= -->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
事务的传播特性
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行
为:
-
propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这
个事务中,这是最常见的选择。 -
propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
-
propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
-
propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
-
propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
-
propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
-
propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
propagation_required类似的操作
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。