Spring的使用
###1、传统的三层架构问题
M:Model
pojo service DAO
V:View
HTML jsp
C:Controller
Servlet
Controller------------------>Service-------------------->DAO
Servlet 提供事务 JDBC|dbutils
整合Controller的框架 以及DAO的框架
SpringMVC
我们可以这样认为:Controller-----依赖---->Service-----依赖----->DAO
![
- 在这里插入图片描述
](https://img-blog.csdnimg.cn/20200616235704933.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1R0MTgxNDk2NDIyNg==,size_16,color_FFFFFF,t_70#pic_center)
2、Spring是什么
Spring是一个用来做对象创建、以及管理对象之间依赖关系的 这样一个框架
管理依赖关系:Controller-----依赖---->Service-----依赖----->DAO
对象创建:原来创建对象(new 反射 对象克隆)----有了Spring之后(Spring帮我们自动创建)
Spring:春天 程序员的春天来了
3、Spring能干什么
3.1、Spring在开发中到底能干吗?
1、为业务逻辑层提供事务
2、整合第三方框架 相当于是整个结构中的一个粘合剂
3、提供了控制器的解决方案
4、提供了控制器的解决方案 JdbcTemplate
5、提供了邮件的整合方案
6、提供了Aop编程的这种思想
7、提供了Web支持的解决方案
8、IOC、DI
3.2、Spring中的七大模块以及功能
Spring Core :IOC DI
Spring Aop :面向切面编程的一些东西
Spring DAO:DAO层的解决方案 ----------->JdbcTemplate
Spring ORM:这个包简单的说 就是提供了 第三方数据库访问的框架的整合 (iBatis、Hibernate)
O:Obeject
R:Relation
M:Mapping
JAVA对象通过映射关系 直接映射到 数据库表 的这样一门技术 其实就是DAO层的解决方案
Spring Web:提供了Web项目的一些支持
Spring WebMVC:Spring MVC------控制器的解决方案
Spring Context:主要提供的是上下文的支持
3.3、Spring的家族都有哪些框架
Spring SpringBoot SpringSecurity SpringCloud(不是一个框架 是一系列做微服务框架的集合)
###4、Spring中的IOC的问题
IOC:控制反转
谁控制了谁?
以前我们创建Java对象的时候 自己创建的 new这种方式去完成
JAVA对象的创建 就不再由我们去创建 而是由Spring自动去创建
Spring控制了Java对象的创建
什么东西反转了?
创建对象的权利给反转了
5、Spring中DI问题
6、Spring的第一个HelloWorld程序
6.1、导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
6.2、在main下创建resources文件夹设置成资源文件
6.3、在resource下创建一个bean-base.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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd"
>
</beans>
6.4、准备一个java类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String userName;
private String password;
}
6.5、在xml中进行对象的申明
<!--说明需要生成一个java对象 然后放到IOC的容器中
id:身份唯一的标识
class:标识的是要生成java的类
-->
<bean id="user" class="com.qf.cd.helloword.User"></bean>
6.6、测试文件
//第一步:我们需要获取这个对象的容器(IOC容器)
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-base.xml");
//第二步:获取这个Java对象
User user = context.getBean(User.class);
//第三步:打印这个对象
System.out.println(user);
7、Spring的实现方式之XML
7.1、基本的配置
<!--说明需要生成一个java对象 然后放到IOC的容器中
id:身份唯一的标识
class:标识的是要生成java的类
name:给当前这个类的对象取名字
scope="prototype":表示的是多例 :多例的时候 java对象并没有 放到容器 是你请求的时候生成对象 返回给你的
"singleton":表示的是单例
init-method="init" :对象放到IOC之前 初始化数据用的
destroy-method:对象销毁之前 还原对象 用的
-->
<bean id="user111"
name="userbobo"
scope="singleton"
init-method="init"
destroy-method="destory"
class="com.qf.cd.helloword.User"></bean>
7.2、有参数对象的对象的构建
<!--带参数的对象怎么实例化?-->
<!--<bean id="user2" class="com.qf.cd.helloword.User">-->
<!--<constructor-arg index="0" value="1"></constructor-arg>-->
<!--<constructor-arg index="1" value="小波波"></constructor-arg>-->
<!--<constructor-arg index="2" value="小王子"></constructor-arg>-->
<!--</bean>-->
<!--<bean id="user3" class="com.qf.cd.helloword.User">-->
<!--<constructor-arg name="id" value="2"></constructor-arg>-->
<!--<constructor-arg name="userName" value="小波2"></constructor-arg>-->
<!--<constructor-arg name="password" value="小王2"></constructor-arg>-->
<!--</bean>-->
7.3、工厂创建对象的方式
<!--工厂创建对象的问题-->
<!--申明工厂-->
<!-- <bean id="userFactory" class="com.qf.cd.helloword.UserFactory"></bean>-->
<!--获取Java对象
factory-bean:这个是factory的工厂对象 注意:值是bean的id的值
factory-method:工厂中创建对象的 非静态的这个方法
-->
<!-- <bean id="user4" factory-bean="userFactory" factory-method="getInstance1"></bean>-->
<!--静态方法构建这样一个对象
factory-method:因为调用的是静态的方法 所以后面是静态方法的这个名字
-->
<bean id="user4" class="com.qf.cd.helloword.UserFactory" factory-method="getStaticInstance"></bean>
7.4、出现的问题
通过类型找对象的时候、如果当前类的实例在IOC容器中存在多个的话 那么 是会报错 因为他不知道你找到是哪一个Java对象
<!--
lazy-init:这个是延迟对象的初始化 在你 getBean的时候 进行对象的初始化
-->
<!--<bean id="user1" class="com.qf.cd.helloword.User" lazy-init="true"> </bean>-->
<!--<bean id="user2" class="com.qf.cd.helloword.User"></bean>-->
<!--
depends-on="userDAO":这个属性可以告诉咋们的IOC容器先初始化谁比较合适
-->
<bean id="userService" class="com.qf.cd.helloword.UserService" depends-on="userDAO,user"></bean>
<bean id="user" class="com.qf.cd.helloword.User"></bean>
<bean id="userDAO" class="com.qf.cd.helloword.UserDAO"></bean>
8、Spring中的DI(依赖注入)
依赖:谁依赖于谁?
在开发中:Controller-----依赖于-----Service-------依赖于DAO
注入了什么东西?
1、JAVA对象
2、可以是注入的咋们的值
8.1、通过构造器进行注入(就是给这个对象赋值)
8.1.1、首先在bean.xml中进行申明
<!--这个是DAO接口-->
<bean id="userDAO" class="com.qf.cd.di.UserDAO"></bean>
<!--这个是业务实现-->
<bean id="userService" class="com.qf.cd.di.UserService">
<!--
如果是一个具体的值 那么就写 Value写值就可以了
如果要注入的是一个对象 那么直接使用ref进行引用就可以了
ref后面的值 一定是这个对象在容器中的这个id值
-->
<constructor-arg name="userDAO" ref="userDAO"></constructor-arg>
</bean>
8.1.2、然后给一个构造器
public class UserService {
private UserDAO userDAO;
public UserService(UserDAO userDAO){
this.userDAO=userDAO;
}
/**
* 登陆
*/
public void login(){
userDAO.aa();
}
}
8.2、通过Set方法进行注入
8.2.1、编写类成员属性的Set方法
private UserDAO userDAO1111;
public void setUserDAO1111(UserDAO userDAO1111) {
this.userDAO1111 = userDAO1111;
}
8.2.2、编写配置文件
<!--通过Set方法进行注入-->
<bean id="userDAO" class="com.qf.cd.di.UserDAO"></bean>
<bean id="userService" class="com.qf.cd.di.UserService">
<!--
property:表示的属性
name:填写的是 成员变量的名称
-->
<property name="userDAO1111" ref="userDAO"></property>
</bean>
8.3、p标签注入
8.3.1、首先编写Set方法(p标签的实质还是Set注入)
private UserDAO userDAO;
// p:标签注入的时候 底层实际上还是 Set注入的方式
// 所以必须要有Set方法
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
8.3.2、编写配置文件
<!--这个是UserDAO的对象-->
<bean id="userDAO" class="com.qf.cd.di.UserDAO"></bean>
<bean id="userService" class="com.qf.cd.di.UserService" p:userDAO-ref="userDAO"></bean>
8.4、内部bean注入
8.4.1、编写set方法
private UserDAO userDAO;
// p:标签注入的时候 底层实际上还是 Set注入的方式
// 所以必须要有Set方法
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
8.4.2、编写配置文件
<!--下面玩下 内部bean注入-->
<bean id="userService" class="com.qf.cd.di.UserService">
<property name="userDAO">
<bean class="com.qf.cd.di.UserDAO"></bean>
</property>
</bean>
总结一下:对象的注入方式:Set注入、另外一种是构造器注入
9、自动装配模型
<bean id="userDAO" class="com.qf.cd.di.UserDAO"></bean>
<!--
autowire:自动装配
byName:通过名字自动的去找 名字相同的java对象 然后赋值给 当前类的成员变量
byType:这个是通过类型进行装配
-->
<bean id="userService" class="com.qf.cd.di.UserService"></bean>
10、注解模式实现IOC、DI功能
@Component:这个注解表示的意思是将类生成对象放到IOC容器中
@Autowired :先通过类型找对象 找不到 再通过名字来找对象 注意
@Resource(type = UserDAO.class) :这个注解是先通过名字 再通过注解来找对象 注意
@PostConstruct:对象放到IOC容器之前 进行初始化的操作
@PreDestroy:对象要销毁之前要进行对象的回收操作
@Repository:这个表示的是对象放到IOC容器中去 //这个注解一般用在DAO层
@Service:这个注解也是将对象放到IOC容器中
注意
@Override
protected void finalize() throws Throwable {
super.finalize();
}
每个对象的这个方法都可以干预对象在JVM回收数据的时候 不被回收
11、代理的设计模式
代理的设计模式解决了什么问题?
代理的设计模式 解决的问题:能够动态的监控一个类 中所有方法的执行 以及在这个方法的执行的前后动态植入咋们的代码
代理:简单的说就是对原来的功能的增强
比如:为业务逻辑层提供事务
@Configuration
Spring整合iBatis
11.1、静态代理
静态代理的前提是 当前的类 必须实现接口否则没法玩
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpDIKyWz-1592322829943)(pic\1592288049671.png)]
11.1.1、被代理类的接口
public interface IUserService {
void zz();
}
11.1.2、被代理类
public class UserService implements IUserService{
/**
* 转账这个方法
*/
public void zz(){
System.out.println("锁定张三的账户");
System.out.println("张三的账户预减1000元");
System.out.println("检测李四的账户是否可用");
System.out.println("李四的账户增加1000元");
}
}
11.1.3、代理类
public class UserServiceProxy implements IUserService{
private IUserService userService;
public UserServiceProxy(IUserService userService ){
this.userService=userService;
}
@Override
public void zz() {
System.out.println("添加事务");
userService.zz();
System.out.println("提交事务");
}
}
11.2、动态代理(JDK代理)
动态:被代理的类的对象是自动生成的
被代理的类是自动生成的
被代理的类的对象也是自动生成的
JDK代理:原因是使用的是JDK本身的API
前提:被代理的类 必须要实现接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cO6a4SVN-1592322829949)(pic\1592290057779.png)]
11.2.1、被代理类实现的接口
public interface IUserService {
void zz();
}
11.2.2、被代理的类
public class UserService implements IUserService {
/**
* 转账这个方法
*/
public void zz(){
System.out.println("锁定张三的账户");
System.out.println("张三的账户预减1000元");
System.out.println("检测李四的账户是否可用");
System.out.println("李四的账户增加1000元");
}
}
11.2.3、代理类实现
public static void main(String[] args){
/**
* 第一个参数:classloader:表示的是类加载器 写法是死的 类.class.getClassLoader
* 第二个参数:interfaces:当前类实现的接口 之所以要这个东西 是因为 生成代理类的时候 需要实现接口
* 1:被代理的是个类:类.class.getInterface
* 2:被代理的是是个接口: new Class[]{接口.class}
* 第三个参数:invationHandle
* 方法的监听的回调接口----当你执行这个接口中的某一个方法的时候就会自动的回调到这个方法中来
*/
IUserService userService= (IUserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
UserService.class.getInterfaces(),
new InvocationHandler() { //执行到每一个方法都会执行到这里来
/**
*
* @param proxy :代理对象
* @param method :当前执行的方法
* @param args :当前执行方法的参数封装
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在方法执行的前后进行拓展
System.out.println("打开事务");
Object invoke = method.invoke(new UserService(), args);
System.out.println("关闭事务");
return invoke;
}
}
);
11.3、CGLIB代理
思考一个问题:
静态代理和动态代理都有一个前提:被代理的类必须实现接口
假设一个类 没有实现接口需要增强 怎么办呢?
CGLIB代理在这种场景下 就应运而生了…
CGLIB代理本身是可以代理任意的一个类 这个类可以不实现接口 也可以实现接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZxXfEQnq-1592322829952)(pic\1592291117537.png)]
11.3.1、被代理的类
public class UserService{
/**
* 转账这个方法
*/
public void zz(){
System.out.println("锁定张三的账户");
System.out.println("张三的账户预减1000元");
System.out.println("检测李四的账户是否可用");
System.out.println("李四的账户增加1000元");
}
}
11.3.2、代理的类
public class UserServiceProxy{
/**
* 获取这个代理类
* @return
*/
public static UserService getUserServiceProxy(){
Enhancer enhancer=new Enhancer();
//设置生成的类的爹是谁
enhancer.setSuperclass(UserService.class);
//设置方法监听的回调
enhancer.setCallback(new MyMethodInterceptor());
return (UserService) enhancer.create();
}
/**
* 方法的监听
*/
static class MyMethodInterceptor implements MethodInterceptor{
/**
*
* @param obj:代理对象
* @param method :当前执行的方法
* @param args :当前执行方法的参数
* @param proxy :这个是方法代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//在这里进行增强
System.out.println("开启事务");
Object invoke = method.invoke(new UserService(), args);
System.out.println("提交事务");
return invoke;
}
}
}
#####11.3.3、测试实现
public class Test001 {
public static void main(String[] args){
UserService userServiceProxy = UserServiceProxy.getUserServiceProxy();
userServiceProxy.zz();
}
}
12、AOP面向切面的编程
什么叫面向切面编程?
就是在编程的时候 将我们的重复的代码抽取出来形成方法 再形成一个类、这个类就是切面类、当我们在执行原来代码的时候 使用代理的设计模式 动态植入我们抽取出来的代码 的这种编程方式就称为 面向切面编程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-839CEaFJ-1592322829955)(pic\1592293344476.png)]
12.1、手动实现下面向切面编程(使用CGLIB代理来实现)
12.1.1、编写业务类
@Component
public class UserService {
/**
* 这是一个add的方法
*/
public void add(){
System.out.println("添加数据完成....");
}
}
12.1.2、编写aop类
@Component
public class Aop {
public void begin(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("提交事务");
}
}
12.1.3、编写代理类
@Component
public class UserServiceProxy implements MethodInterceptor {
@Autowired
Aop aop;
/**
* 获取代理类
* @return
*/
public UserService getUserServiceProxy(){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(this);
return (UserService) enhancer.create();
}
/**
* 这里就是方法的拦截
* @param obj
* @param method
* @param args
* @param proxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
aop.begin();
Object invoke = method.invoke(new UserService(), args);
aop.commit();
return invoke;
}
}
12.1.4、编写配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd"
>
<context:component-scan base-package="com.qf.cd.aop.sd"></context:component-scan>
</beans>
12.1.5、编写测试类
public class Test001 {
public static void main(String[] args){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:bean-aop1.xml");
UserService userServiceProxy = context.getBean(UserServiceProxy.class).getUserServiceProxy();
userServiceProxy.add();
}
}