spring(上)

spring是于2003年兴起的一款轻量级的,非侵入式的IOC和AOP的一站式的java开发框架,为简化企业级应用开发而生
轻量级的:指的是spring核心功能的jar包不大。
非侵入式的:业务代码不需要继承或实现spring中任何的类或接口
IOC:控制反转(Inverse of Control),以前项目都是在哪儿用到对象,在哪儿new,把生成对象的权利反转给spring框架(让spring把对象管理起来,在哪用在哪注入)
AOP:面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
一站式框架

  • 提供核心功能,主要是IOC,创建管理对象;
  • 提供面向切面编程,增强程序扩展;
  • 对数据访问层进行了封装(重点在于事务管理)
  • 对web层进行封装,使得请求更加便捷

Spring Hello World搭建

1.Maven 导入 spring 核心基础 jar


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-contextartifactId>
    <version>5.2.2.RELEASEversion>
dependency>

2.编写一个Admin实体类

package com.ffyc.ssm.model;

public class Admin {
    private Integer id;
    private String account;

    public Admin() {
        System.out.println("admin无参构造");
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }
}

3.编写 spring 配置文件,在resources/spring.xml中


<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 id="admin" class="com.ffyc.ssm.model.Admin">bean>
beans>

4.测试spring
读取spring配置文件,并对文件中配置的对象进行创建

package com.ffyc.ssm.test;

public class Test1 {
    public static void main(String[] args) {
        /*以前使用对象方式,在哪儿用,在哪儿new
        new Admin();
        spring思想是,由框架统一对项目中的类进行管理(创建对象,后期增强一些功能),在需要的地方注入即可*/
        //Map(admin,new Admin)
        //ClassPathXmlApplicationContext就是spring中的实际实现者
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        //Object admin=app.getBean("admin");//不知道返回的类型,从Map中拿出new Admin对象
        Admin admin=app.getBean("admin",Admin.class);//明确类型
        System.out.println(admin);
    }
}

IOC(控制反转)

正控:若要使用某个对象,需要自己去负责对象的创建
反控:若要使用某个对象,只需要从 Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了 Spring 框架
**底层实现方式:**解析 xml/扫描注解标签 + 工厂模式 + 反射机制

Spring Bean 管理

1、基于 xml 配置方式

配置需要让spring进行管理的类
id=“唯一的标识”
class=“让spring管理的类名”
bean对象?由spring框架创建并管理的对象

  • Scope=“singleton 默认值”,单例的,在整个应用程序中只创建一个对象,在spring框架启动时就创建好了
  • scope=“prototype”,原型的,每次获取时创建一个对象,可以创建多个

<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 id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">bean>
beans>
public class Test1 {
    public static void main(String[] args) {
        //读取spring配置文件,并对文件中配置的对象进行创建
        //ClassPathXmlApplicationContext就是spring中的实际实现者
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        Admin admin1=app.getBean("admin",Admin.class);
        System.out.println(admin);
        System.out.println(admin1);
    }
}
/*
admin无参构造
admin无参构造
com.ffyc.ssm.model.Admin@685cb137
com.ffyc.ssm.model.Admin@6a41eaa2
*/

spring框架创建对象(控制反转)时,为对象的属性进行赋值操作(这个赋值操作称为依赖注入
1.属性赋值 getXXX、setXXX方法

<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
    <property name="id" value="10">property>
    <property name="account" value="张三">property>
bean>
public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        System.out.println(admin);
    }
}
/*
admin无参构造
Admin{id=10, account='张三'}
*/

2.构造方法赋值

<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
    <constructor-arg name="id" value="1">constructor-arg>
    <constructor-arg name="account" value="1">constructor-arg>
bean>
public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        System.out.println(admin);
    }
}
//Admin{id=1, account='1'}

在一个方法中注入另一个方法

<bean id="admin" class="com.ffyc.ssm.model.Admin" scope="prototype">
    <constructor-arg name="id" value="1">constructor-arg>
    <constructor-arg name="account" value="1">constructor-arg>
bean>
<bean id="adminDao" class="com.ffyc.ssm.dao.AdminDao">bean>
<bean id="adminService" class="com.ffyc.ssm.service.AdminService">
    <property name="adminDao" ref="adminDao">property> 
bean>
public class Test2 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        AdminService adminService=app.getBean("adminService",AdminService.class);
        adminService.save(admin);
    }
}

2、注解方式实现(建议)

1、注解需要的jar包
注解功能封装在AOP包中,导入 Spring aop jar 包即可


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-contextartifactId>
    <version>5.2.2.RELEASEversion>
dependency>

2、开启注解扫描


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:component-scan base-package="com.ffyc.ssm"> context:component-scan>
beans>

3、注解创建对象
有注解标签才是spring管理的对象,并创建对象
1.@Component(value = “admin”) 一般用于模型类,等同于
2.@Scope(value=“prototype”) 原型(多次)
@Scope(value=“singleton”) 单例(一次)

@Component(value = "admin")
@Scope(value = "singleton")

3.@Repository(value = “adminDao”),用于dao层

@Repository(value = "adminDao")
public class AdminDao {
    public void saveAdmin(Admin admin){
        System.out.println("保存管理员"+admin);
    }
}

4.@Service(value = “adminService”)
5.@Autowired,spring框架提供的一种自动注入的注解标签,可以写在字段和 setter 方法上。如果写在字段上,那么就不需要再写 setter 方法。默认情况下它要求依赖对象必须存在,如果允许 null 值,可以设置它的 required 属性为 false。
有两种方式去查找对象:

  • byType,去spring容器中根据当前类型搜索,@Autowired
  • byName,通过名称查找,需要结合 @Qualifier(value=“adminDao”),value值和@Repository(value = “adminDao”)里面的value对应
    6.@Resource,是jdk中提供的一个注解标签
  • byType,去spring器中根据当前类型搜索,@Resource
  • byName,通过名称查找,@Resource(name = “adminDao”)
    Autowired(required=true),注入时,对象值不能为空,为空报错
@Service(value = "adminService")
public class AdminService {
    /*@Autowired
     @Qualifier(value = "adminDao")
    AdminDao adminDao;//依赖注入*/
    
    //@Resource
    @Resource(name = "adminDao")
    AdminDao adminDao;

    public void save(Admin admin){
        adminDao.saveAdmin(admin);
    }
}
public class Test3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        AdminService adminService=app.getBean("adminService",AdminService.class);
        adminService.save(admin);
    }
}

3、注解与 XML 的对比

注解优点: 方便、直观、高效(代码少,没有配置文件的书写那么复杂)。
**注解缺点:**以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的(通过maven把项目重新编译compile一下)。
xml 优点是: 配置和代码是分离的,在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
**xml 缺点是:**编写麻烦,效率低,大型项目过于复杂

Spring JDBC

spring框架中的JDBC功能

  1. jdbc封装: JdbcTemplate(了解即可 后面常用mybatis),事务管理(重点)
  2. ioc实际的应用
    Spring 是个一站式框架:Spring 自身也提供了控制层的 SpringMVC 和 持久层的 Spring JdbcTemplate。
    1.下载 Spring JdbcTemplate 的 jar 包
    导入jdbc模块依赖

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>5.2.2.RELEASEversion>
dependency>

导入mysql


<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>8.0.16version>
dependency>

导入阿里巴巴提供的数据源管理组件,数据源组件封装了连接数据库,还有数据库连接池功能
druid(德鲁伊),常用的数据库链接池组件:dbcp、c3p0


<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.10version>
dependency>

2.config.properties

classDriverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai
uname=root
pwd=123456

3.db.xml


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    
    
    <context:property-placeholder location="classpath:config.properties">context:property-placeholder>
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${classDriverName}">property>
        <property name="url" value="${url}">property>
        <property name="username" value="${uname}">property>
        <property name="password" value="${pwd}">property>
        <property name="initialSize" value="5">property>
        <property name="maxActive" value="10">property>
    bean>
    
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource">property>  
    bean>
    
beans>

4.spring.xml注解db.xml

<import resource="classpath:db.xml">import> 

增删改用update

@Repository(value = "adminDao")
public class AdminDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
    
   public void saveAdmin(Admin admin){
        //jdbcTemplate.update("insert into admin(account,password)value(?,?)","aaa","111");
        jdbcTemplate.update("delete from admin where id =?","5");
    }
}

查询,返回单个结果

public void saveAdmin(Admin admin){
    Admin admin2=jdbcTemplate.queryForObject("select * from admin where id=?",
            new RowMapper<Admin>() {
                @Override
                public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
                    Admin admin1=new Admin();
                    admin1.setId(resultSet.getInt("id"));
                    admin1.setAccount(resultSet.getString("account"));
                    return admin1;
                }
            },1);
    System.out.println(admin2);
}

查询,返回多个结果

public void saveAdmin(Admin admin){
    List<Admin> adminList=jdbcTemplate.query("select * from admin",
            new RowMapper<Admin>() {
                @Override
                public Admin mapRow(ResultSet resultSet, int i) throws SQLException {
                    Admin admin1=new Admin();
                    admin1.setId(resultSet.getInt("id"));
                    admin1.setAccount(resultSet.getString("account"));
                    return admin1;
                }
            });
    System.out.println(adminList);
}

AOP

不使用 AOP 的开发方式

案例:
先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要写两个非业务方法。非业务方法也称为交叉业务逻辑:

  • doTransaction():用于事务处理
  • doLog():用于日志处理
    然后,再使接口方法调用它们。接口方法也称为主业务逻辑.
    spring(上)_第1张图片
    在方法中想要实现额外功能时,需要在业务代码中显示调用.
    spring(上)_第2张图片
    即使抽取一个工具类,将这些方法封装起来,依然还是需要显示调用.
    spring(上)_第3张图片

AOP概述

AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,AOP 可以**对业务逻辑和非业务逻辑进行隔离,从而使得各部分之间的耦合度降低,提高程序的可重用性,**同时提高了开发的效率。将程序中的一些非业务代码进行提取,在不需要修改原来代码的情况下,为程序添加额外的功能
AOP思想不是spring框架特有的,只是spring框架引入使用了这一思想。
面向切面编程的好处就是: 减少重复,专注业务;
注意:面向切面编程只是面向对象编程的一种补充。
核心原理: 使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑.
非业务代码使用案例:

  • 事务处理:开启事务,关闭事务,出现异常后回滚事务
  • 验证权限:在执行方法前,判断是否具有权限
  • 打印日志:在执行前进行日志处
  • 统一异常处理
    spring(上)_第4张图片
    是怎么做到的?底层实现:使用的是动态代理模式。是通过一个代理对象来实现对非业务代码进行调用的。告诉代理对象,调用哪个方法时,让代理对象去帮助我们调用哪个方法
    代理对象(相当于4s 中介 手机店)

AOP的基本概念

**连接点(Joinpoint):**类中可以被增强的方法
**切入点(pointcut):**类中有很多方法可以被增强,但实际中只有 add 和 update被增了,那么 add 和 update 方法就被称为切入点(类中实际被增强的方法)
通知(Advice): 指提取的非业务的功能。通知分为:前置通知、后置通知、异常通知、最终通知、环绕通知
**切面(Aspect):**把通知添加到切入点的整个过程
目标(Target): 代理的目标对象(连接点,切入点所在类AdminDao)
代理(Proxy): 向目标对象应用通知时创建的代理对象

springAOP实现

有两种实现方式:1.xml配置方式 2.注解方式

1、xml配置方式

对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程。
AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实现方式更为简捷,使用更为方便, 而且还支持注解式开发。所以,spring中引入了一个AspectJ的aop框架.
下载 AOP 相关 jar

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-aspectsartifactId>
    <version>5.2.2.RELEASEversion>
dependency>

<import resource="classpath:aopDemo.xml">import>

基于 aspectj 的 xml 配置方式实现。
先把类交给spring管理,这样spring生成的代理对象才可以调用



<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
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    
    <bean id="myutil" class="com.ffyc.ssm.util.MyUtil">bean>

    <aop:config>
        
        <aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))"/>
        
        <aop:aspect ref="myutil">
            
            <aop:before method="printLog" pointcut-ref="saveAdmin">aop:before>
        aop:aspect>
    aop:config>
beans>
package com.ffyc.ssm.util;
   /* 提取的非业务的功能称为通知
    通知又分为5种: 前置通知、后置通知、异常通知、最终通知、环绕通知*/
public class MyUtil {
    public void printLog(){
        System.out.println("打印日志");
    }
    public void commit(){
        System.out.println("提取事务");
    }
    public void exceptionAdvice(Throwable e){
        System.out.println("异常通知"+e.getMessage());
    }
}
package com.ffyc.ssm.dao;

@Repository(value = "adminDao")
//目标类
public class AdminDao {
    @Autowired
    JdbcTemplate jdbcTemplate;

    /*连接点:类中可以被增强的方法,称为连接点
    切入点: 类中实际被增强的方法,横切面切入的方法*/

    public void saveAdmin(Admin admin){
        System.out.println("保存管理员");
    }

    public void updateAdmin(Admin admin){
        System.out.println("修改管理员");
    }
}
public class Test3 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext app=new ClassPathXmlApplicationContext("spring.xml");
        Admin admin=app.getBean("admin",Admin.class);
        AdminService adminService=app.getBean("adminService",AdminService.class);
        adminService.save(admin);
    }
}

spring(上)_第5张图片
通知又分为5种:
前置通知:业务方法执行前调用
后置通知(after-returning):业务方法执行后调用,当方法出现异常不执行
异常通知 (after-throwing):业务方法出现异常时调用
最终通知(after):业务方法执行后调用,当方法出现异常也会执行
环绕通知,环绕通知包含前四种通知

package com.ffyc.ssm.util;

public class MyUtil {
    /*ProceedingJoinPoint需要调用的方法*/
    public void aroundAdvice(ProceedingJoinPoint point){
        try {
            System.out.println("前置通知");
            point.proceed();//调用我们自己的业务方法
            System.out.println("后置通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知"+throwable.getMessage());
        }
        System.out.println("最终通知");
    }
}
<aop:config>
    
    <aop:pointcut id="saveAdmin" expression="execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))"/>
    
    <aop:aspect ref="myutil">
        <aop:around method="aroundAdvice" pointcut-ref="saveAdmin">aop:around>
    aop:aspect>
aop:config>
2、注解方式的实现

1.开启自动代理


<aop:aspectj-autoproxy />

2.@Component //让spring管理生成对象
@Aspect //表明装有通知的类/切面

package com.ffyc.ssm.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component //让spring管理生成对象
@Aspect  //表明装有通知的类/切面
public class MyUtil {
    //@Before("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
    //@AfterReturning("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
    //@After("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
    public void printLog(){
        System.out.println("打印日志");
    }
    public void commit(){
        System.out.println("提取事务");
    }
    //@AfterThrowing(value = "execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))",throwing = "e")
    public void exceptionAdvice(Throwable e){
        System.out.println("异常通知"+e.getMessage());
    }
    
    /*ProceedingJoinPoint需要调用的方法*/
    @Around("execution(* com.ffyc.ssm.dao.AdminDao.saveAdmin(..))")
    public void aroundAdvice(ProceedingJoinPoint point){
        try {
            System.out.println("前置通知");
            point.proceed();//调用我们自己的业务方法
            System.out.println("后置通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知"+throwable.getMessage());
        }
        System.out.println("最终通知");
    }
}

你可能感兴趣的:(spring,java,后端)