千家信息网

Spring[02.基础知识整理(下)]

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,Bean使用外部属性文件在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分
千家信息网最后更新 2024年09月22日Spring[02.基础知识整理(下)]

Bean使用外部属性文件

  • 在配置文件里配置 Bean 时, 有时需要在 Bean 的配置里混入系统部署的细节信息(例如: 文件路径, 数据源配置信息等). 而这些部署细节实际上需要和 Bean 配置相分离

  • Spring 提供了一个 PropertyPlaceholderConfigurer 的 BeanFactory 后置处理器, 这个处理器允许用户将 Bean 配置的部分内容外移到属性文件中. 可以在 Bean 配置文件里使用形式为 ${var} 的变量, PropertyPlaceholderConfigurer 从属性文件里加载属性, 并使用这些属性来替换变量.

  • xml context加载外部配置文件

Spel表达式

是一个支持运行时查询和操作对象图的强大的表达式语言

通过 SpEL 可以实现:

  • 通过 bean 的 id 对 bean 进行引用
  • 调用方法以及引用对象中的属性
  • 计算表达式的值
  • 正则表达式的匹配

案例

验证邮箱

^[_A-Za-z0-9-]+(\.[_A-Za-z0-9-]+)"+"*@[A-Za-z0-9]+(\.[A-Za-z0-9]+)*(\.[A-Za-z]{2,})$

Bean的生命周期

生命周期

  • Spring IOC 容器可以管理 Bean 的生命周期, Spring 允许在 Bean 生命周期的特定点执行定制的任务.
  • Spring IOC 容器对 Bean 的生命周期进行管理的过程:
    • 通过构造器或工厂方法创建 Bean 实例
    • 为 Bean 的属性设置值和对其他 Bean 的引用
    • 调用 Bean 的初始化方法
    • Bean 可以使用了
    • 当容器关闭时, 调用 Bean 的销毁方法
  • 在 Bean 的声明里设置 init-method 和 destroy-method 属性, 为 Bean 指定初始化和销毁方法.

Bean后置处理器

基本介绍
  • Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
  • Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例. 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.
  • 对Bean 后置处理器而言, 需要实现BeanPostProcessor接口.

在初始化方法被调用前后, Spring 将把每个 Bean 实例分别传递给上述接口的以下两个方法:

public class MyBeanPostProcesser implements BeanPostProcessor {    // 在init-method之前调用    @Override    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {        System.out.println("postProcessBeforeInitialization:  " + s);        return o;    }    // 在init-method之后调用    @Override    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {        System.out.println("postProcessAfterInitialization:  " + s);        return o;    }}
后置处理器特性

//Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理.
//Bean 后置处理器对 IOC 容器里的所有 Bean 实例逐一处理, 而非单一实例.
// 其典型应用是: 检查 Bean 属性的正确性或根据特定的标准更改 Bean 的属性.

//采用前置和后置处理之后
//首先运行构造函数
//然后给属性赋值
//然后访问前置处理函数
//然后访问init函数
//然后访问后置处理函数
//然后输出结果
//最后访问destroy函数

@Autowired 自动装配 Bean

  • 构造器, 普通字段(即使是非 public), 一切具有参数的方法都可以应用@Authwired 注解
    默认情况下, 所有使用 @Authwired 注解的属性都需要被设置. 当 Spring 找不到匹配的 Bean 装配属性时, 会抛出异常, 若某一属性允许不被设置, 可以设置 @Authwired 注解的 required 属性为 false

  • 默认情况下, 当 IOC 容器里存在多个类型兼容的 Bean 时, 通过类型的自动装配将无法工作. 此时可以在 @Qualifier 注解里提供 Bean 的名称. Spring 允许对方法的入参标注 @Qualifiter 已指定注入 Bean 的名称

  • @Authwired 注解也可以应用在数组类型的属性上, 此时 Spring 将会把所有匹配的 Bean 进行自动装配.

  • @Authwired 注解也可以应用在集合属性上, 此时 Spring 读取该集合的类型信息, 然后自动装配所有与之兼容的 Bean.

  • @Authwired 注解用在 java.util.Map 上时, 若该 Map 的键值为 String, 那么 Spring 将自动装配与之 Map 值类型兼容的 Bean, 此时 Bean 的名称作为键值

AOP与AspectJ

概述

是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.

AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点.

在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里.

AOP 的好处:

  • 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级
  • 业务模块更简洁, 只包含核心业务代码.

术语

  • 切面(Aspect): 横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
  • 通知(Advice): 切面必须要完成的工作
  • 目标(Target): 被通知的对象
  • 代理(Proxy): 向目标对象应用通知之后创建的对象
  • 连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。例如 ArithmethicCalculator#add() 方法执行前的连接点,执行点为 ArithmethicCalculator#add(); 方位为该方法执行前的位置
  • 切点(pointcut):每个类都拥有多个连接点:例如 ArithmethicCalculator 的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP 通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

AspectJ

AspectJ:Java 社区里最完整最流行的 AOP 框架.在 Spring2.0 以上版本中, 可以使用基于 AspectJ 注解或基于 XML 配置的 AOP

依赖包:

  • aopalliance-1.0.jar
  • aspectjrt.jar
  • aspectjtools.jar
  • aspectjweaver.jar
  • org.aspectj.matcher.jar

AspectJ通知注解

  • @Before: 前置通知, 在方法执行之前执行
  • @After: 后置通知, 在方法执行之后执行
  • @AfterRunning: 返回通知, 在方法返回结果之后执行
  • @AfterThrowing: 异常通知, 在方法抛出异常之后
  • @Around: 环绕通知, 围绕着方法执行

    切入点合并

  • @Pointcut 将多个被限制的bean或者bean方法合并为一个集合,AspectJ通知注解可以直接调用合并切入点的方法,
    如: combinePointCut

    Order

  • 制定切面的优先级
  • 数字越小,代表优先级越高

案例

@Aspect@Order(0)public class AspectProcessor {    // 合并切入点    @Pointcut("execution(* com.demo.aop.aspect.CalculatorImpl.*(..)))")    public void combinePointCut(){}    // 此函数在指定的bean方法执行前响应    // @Before("execution (* com.demo.aop.aspect.CalculatorImpl.*(..))")    @Before("combinePointCut()")    public void beforeAspectProcessor(JoinPoint joinPoint){        System.out.println("beforeAspectProcessor method name: " + joinPoint.getSignature().getName());        System.out.println("beforeAspectProcessor method args: " + Arrays.asList(joinPoint.getArgs()));    }    // 此函数在指定的bean方法执行后响应    // @After("execution (* com.demo.aop.aspect.CalculatorImpl.*(..))")    @After("combinePointCut()")    public void afterAspectProcessor(JoinPoint joinPoint){        System.out.println("afterAspectProcessor method name: " + joinPoint.getSignature().getName());        System.out.println("afterAspectProcessor method args: " + Arrays.asList(joinPoint.getArgs()));    }//    此函数在指定的bean方法执行前、后响应//    @Around("combinePointCut()")//    public void around(ProceedingJoinPoint pjp) throws Throwable{//        System.out.println("已经记录下操作日志@Around 方法执行前");//        pjp.proceed();//        System.out.println("已经记录下操作日志@Around 方法执行后");//    }    // 如果只想在连接点返回的时候记录, 应使用返回通知代替后置通知    @AfterReturning(value = "combinePointCut()", returning = "result")    public void afterReturningAspectProcessor(JoinPoint joinPoint, Object result){        System.out.println("afterReturningAspectProcessor method name: " + joinPoint.getSignature().getName());        System.out.println("afterReturningAspectProcessor method args: " + Arrays.asList(joinPoint.getArgs()));        System.out.println("afterReturningAspectProcessor method result: " + result);    }    // 异常通知    @AfterThrowing(value = "combinePointCut()", throwing = "e")    public void afterThrowingAspectProcessor(JoinPoint joinPoint, Exception e){        System.out.println("afterThrowingAspectProcessor method name: " + joinPoint.getSignature().getName());        System.out.println("afterThrowingAspectProcessor method args: " + Arrays.asList(joinPoint.getArgs()));        System.out.println("afterThrowingAspectProcessor method throwing: " + e);    }}
  • 将 aop Schema 添加到 根元素中.
  • 要在 Spring IOC 容器中启用 AspectJ 注解支持, 只要在 Bean 配置文件中定义一个空的 XML 元素
  • 当 Spring IOC 容器侦测到 Bean 配置文件中的 元素时, 会自动为与 AspectJ 切面匹配的 Bean 创建代理



通过代理方式实现AspectJ

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;/** * Created by plusplusxu on 2017/10/23. * * 动态代理模式主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法, * 在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法), * 因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象, * 具体应用的话,比如可以添加调用日志,做事务控制等。 * 动态代理是设计模式当中代理模式的一种。 */@Repositorypublic class CalculatorImplProxy {    @Autowired    private Calculator target;    public Calculator getProxy(){        Calculator proxy = null;        // 代理对象由哪一个加载器加载        ClassLoader loader = target.getClass().getClassLoader();        // 代理对象的内容        Class[] interfaces = new Class[]{Calculator.class};        // 当调用代理对象的方法的时候,该方法被执行        InvocationHandler h = new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                // 代理对象方法执行前操作                System.out.println("method: " + method.getName() + "  " + "  args:  " + Arrays.asList(args));                Object result = method.invoke(target, args);                // 代理对象方法执行后操作                System.out.println("method: " + method.getName() + "  " + "  args:  " + Arrays.asList(args) + "  result: " + result);                return result;            }        };        proxy = (Calculator)Proxy.newProxyInstance(loader, interfaces, h);        return proxy;    }}

JDBC

JdbcTemplate

作为 Spring JDBC 框架的核心, JDBC 模板的设计目的是为不同类型的 JDBC 操作提供模板方法. 每个模板方法都能控制整个过程, 并允许覆盖过程中的特定任务. 通过这种方式, 可以在尽可能保留灵活性的情况下, 将数据库存取的工作量降到最低.

  • 每次使用都创建一个 JdbcTemplate 的新实例, 这种做法效率很低下.
  • JdbcTemplate 类被设计成为线程安全的, 所以可以再 IOC 容器中声明它的单个实例, 并将这个实例注入到所有的 DAO 实例中.
  • JdbcTemplate 也利用了 Java 1.5 的特定(自动装箱, 泛型, 可变长度等)来简化开发

JdbcDaoSupport

该类声明了 jdbcTemplate 属性, 它可以从 IOC 容器中注入, 或者自动从数据源中创建.

package com.mysql;import org.springframework.jdbc.core.BatchPreparedStatementSetter;import org.springframework.jdbc.core.JdbcTemplate;import java.sql.PreparedStatement;import java.sql.SQLException;import java.util.List;/** * Created by plusplusxu on 2017/10/25. * * 操作mysql的数据类 * * JdbcTemplate 类被设计成为线程安全的, 所以可以再 IOC 容器中声明它的单个实例, 并将这个实例注入到所有的 DAO 实例中. */public class ProjectDao {    public ProjectDao(JdbcTemplate jdbcTemplateObject) {        this.jdbcTemplateObject = jdbcTemplateObject;    }    public ProjectDao() {    }    public JdbcTemplate getJdbcTemplateObject() {        return jdbcTemplateObject;    }    public void setJdbcTemplateObject(JdbcTemplate jdbcTemplateObject) {        this.jdbcTemplateObject = jdbcTemplateObject;    }    // spring 提供的访问数据库的工具类,需要配置javax.sql.DataSource    // 本例中在applicationContext中配置的mysql数据源    private JdbcTemplate jdbcTemplateObject;    // 添加一条项目记录    // tbl_devops_project为vsdo数据库的项目表(Project)    public void addproject(Project project) {        String sql = "INSERT INTO tbl_devops_project(name,public,language,description," +                "admin, members, gitlab_id,gitlab_url,code_styles,sonar_lint_server_url) " +                "VALUES(?,?,?,?,?,?,?,?,?,?)";        try {            jdbcTemplateObject.update(sql, project.getName(),project.getPub(),project.getLanguage(),project.getDescription(),                    project.getAdmin(),project.getMembers(),project.getGitlab_id(),                    project.getGitlab_url(),project.getCode_styles(),project.getSonar_lint_server_url());        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 根据项目名删除记录    public void delprojectbyname(String name) {        String sql = "DELETE FROM tbl_devops_project WHERE name=?";        try {            jdbcTemplateObject.update(sql,name);        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 删除所有项目    public void delallproject() {        String sql = "DELETE FROM tbl_devops_project";        try {            jdbcTemplateObject.update(sql);        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 更新某个项目    public void updproject(Project project) {        String sql = "UPDATE tbl_devops_project set description=? WHERE name=?";        try {            jdbcTemplateObject.update(sql,project.getDescription(), project.getName());        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 获取所有项目    public List allproject() {        List projects = null;        String sql = "SELECT * FROM tbl_devops_project";        try {            // ProjectMapper 项目表的映射类            projects = jdbcTemplateObject.query(sql, new ProjectMapper());        }        catch (Exception e){            System.out.println(e);        }        return projects;    }    // 查询项目名对应的记录    public List queryprojectbyname(String name) {        List projects = null;        String sql = "SELECT * FROM tbl_devops_project WHERE name=?";        try {            projects = jdbcTemplateObject.query(sql, new Object[]{name}, new ProjectMapper());        }        catch (Exception e){            System.out.println(e);        }        return projects;    }    // 打印所有项目    public void displayall(){        List projects = allproject();        for(Project s : projects){            System.out.println(s);        }    }    // 批量插入    public void insertBatch(final List projects){        String sql = "INSERT INTO tbl_devops_project(name,public,language,description," +                "admin, members, gitlab_id,gitlab_url,code_styles,sonar_lint_server_url) " +                "VALUES(?,?,?,?,?,?,?,?,?,?)";        jdbcTemplateObject.batchUpdate(sql, new BatchPreparedStatementSetter() {            @Override            public void setValues(PreparedStatement ps, int i) throws SQLException {                Project project = projects.get(i);                ps.setString(1, project.getName());                ps.setBoolean(2, project.getPub());                ps.setString(3, project.getLanguage());                ps.setString(4, project.getDescription());                ps.setString(5, project.getAdmin());                ps.setString(6, project.getMembers());                ps.setInt(7, project.getGitlab_id());                ps.setString(8, project.getGitlab_url());                ps.setString(9, project.getCode_styles());                ps.setString(10, project.getSonar_lint_server_url());            }            @Override            public int getBatchSize() {                return projects.size();            }        });    }}
package com.mysql;import org.springframework.jdbc.core.BatchPreparedStatementSetter;import org.springframework.jdbc.core.support.JdbcDaoSupport;import java.sql.PreparedStatement;import java.sql.SQLException;import java.util.List;/** * Created by plusplusxu on 2017/10/26. * * 继承于JdbcDaoSupport,直接封装了JdbcTemplate,写起来更方便 * * 该类声明了 jdbcTemplate 属性, 它可以从 IOC 容器中注入, 或者自动从数据源中创建. * */public class JdbcDaoSupportImpl extends JdbcDaoSupport {    // 添加一条项目记录    // tbl_devops_project为vsdo数据库的项目表(Project)    public void addproject(Project project) {        String sql = "INSERT INTO tbl_devops_project(name,public,language,description," +                "admin, members, gitlab_id,gitlab_url,code_styles,sonar_lint_server_url) " +                "VALUES(?,?,?,?,?,?,?,?,?,?)";        try {            this.getJdbcTemplate().update(sql, project.getName(),project.getPub(),project.getLanguage(),project.getDescription(),                    project.getAdmin(),project.getMembers(),project.getGitlab_id(),                    project.getGitlab_url(),project.getCode_styles(),project.getSonar_lint_server_url());        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 根据项目名删除记录    public void delprojectbyname(String name) {        String sql = "DELETE FROM tbl_devops_project WHERE name=?";        try {            this.getJdbcTemplate().update(sql,name);        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 删除所有项目    public void delallproject() {        String sql = "DELETE FROM tbl_devops_project";        try {            this.getJdbcTemplate().update(sql);        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 更新某个项目    public void updproject(Project project) {        String sql = "UPDATE tbl_devops_project set description=? WHERE name=?";        try {            this.getJdbcTemplate().update(sql,project.getDescription(), project.getName());        }        catch (Exception e){            System.out.println(e);        }        return ;    }    // 获取所有项目    public List allproject() {        List projects = null;        String sql = "SELECT * FROM tbl_devops_project";        try {            // ProjectMapper 项目表的映射类            projects = this.getJdbcTemplate().query(sql, new ProjectMapper());        }        catch (Exception e){            System.out.println(e);        }        return projects;    }    // 查询项目名对应的记录    public List queryprojectbyname(String name) {        List projects = null;        String sql = "SELECT * FROM tbl_devops_project WHERE name=?";        try {            projects = this.getJdbcTemplate().query(sql, new Object[]{name}, new ProjectMapper());        }        catch (Exception e){            System.out.println(e);        }        return projects;    }    // 打印所有项目    public void displayall(){        List projects = allproject();        for(Project s : projects){            System.out.println(s);        }    }    // 批量插入    public void insertBatch(final List projects){        String sql = "INSERT INTO tbl_devops_project(name,public,language,description," +                "admin, members, gitlab_id,gitlab_url,code_styles,sonar_lint_server_url) " +                "VALUES(?,?,?,?,?,?,?,?,?,?)";        this.getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {            @Override            public void setValues(PreparedStatement ps, int i) throws SQLException {                Project project = projects.get(i);                ps.setString(1, project.getName());                ps.setBoolean(2, project.getPub());                ps.setString(3, project.getLanguage());                ps.setString(4, project.getDescription());                ps.setString(5, project.getAdmin());                ps.setString(6, project.getMembers());                ps.setInt(7, project.getGitlab_id());                ps.setString(8, project.getGitlab_url());                ps.setString(9, project.getCode_styles());                ps.setString(10, project.getSonar_lint_server_url());            }            @Override            public int getBatchSize() {                return projects.size();            }        });    }}
                                                                                                                                

事务

事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.

事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用

事务的四个关键属性(ACID)

  • 原子性(atomicity): 事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用.
  • 一致性(consistency): 一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中.
  • 隔离性(isolation): 可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏.
  • 持久性(durability): 一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中.

Spring 既支持编程式事务管理, 也支持声明式的事务管理.

  • 编程式事务管理: 将事务管理代码嵌入到业务方法中来控制事务的提交和回滚. 在编程式管理事务时, 必须在每个事务操作中包含额外的事务管理代码.
  • 声明式事务管理: 大多数情况下比编程式事务管理更好用. 它将事务管理代码从业务方法中分离出来, 以声明的方式来实现事务管理. 事务管理作为一种横切关注点, 可以通过 AOP 方法模块化. Spring 通过 Spring AOP 框架支持声明式事务管理.

用 @Transactional 注解声明式地管理事务

Spring 还允许简单地用 @Transactional 注解来标注事务方法.

  • 为了将方法定义为支持事务处理的, 可以为方法添加 @Transactional 注解. 根据 Spring AOP 基于代理机制, 只能标注公有方法.

  • 可以在方法或者类级别上添加 @Transactional 注解. 当把这个注解应用到类上时, 这个类中的所有公共方法都会被定义成支持事务处理的.
  • 在 Bean 配置文件中只需要启用 元素, 并为之指定事务管理器就可以了.
  • 如果事务处理器的名称是 transactionManager, 就可以在 元素中省略 transaction-manager 属性. 这个元素会自动检测该名称的事务处理器.

事务的传播行为

当事务方法被另一个事务方法调用时, 必须指定事务应该如何传播. 例如: 方法可能继续在现有事务中运行, 也可能开启一个新事务, 并在自己的事务中运行.

方法 事务 属性 处理 项目 管理 注解 对象 数据 配置 事务管理 实例 容器 连接点 代理 应用 处理器 文件 函数 支持 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 山政网络安全系统 棋牌游戏用什么软件开发 华为网络技术教程 思科网络技术学院实验手册 计算机测控与网络技术是什么 数据库三个约束完整性有效性 做小程序要不要买服务器 论述对三大数据库的摘要 软件开发全流程管理软件 苏州五金erp软件开发 贵州mapgis数据库 杭州芒果互联网络科技有限公司 南宁市云驰联科网络技术公司 石阡天然气收费软件开发 网络安全保护制度是保护什么的 沙井租房软件开发 大数据与网络安全概念 战地1无法连接至ea服务器 db2获取当前数据库ip 招远直播软件开发推荐 网络安全保证函 思科网络技术学院实验手册 局域网中的数据库是干什么的 河南商都网络安全知识 玉溪软件开发培训学院 软件开发BSP方向 国内公司是如何保护网络安全的 怎样应对网络安全人才短缺 联通采用的网络技术有哪些 游戏服务器带宽多少钱
0