Java安全(十三) SSM-Spring框架

概述

Spring 是目前主流的 Java Web 开发框架,是一个轻量级的开源框架,具有很高的凝聚力和吸引力。

Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

Spring 是分层的 Java SE/EE 一站式轻量级开源框架,以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核。

  • IoC 指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们使用 new 创建,而使用 Spring 之后,对象的创建都交给了 Spring 框架。
  • AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。

在 Spring 中,认为一切 Java 类都是资源,而资源都是类的实例对象(Bean),容纳并管理这些 Bean 的是 Spring 所提供的 IoC 容器,所以 Spring 是一种基于 Bean 的编程

Why Spring

如果我们有一个接口

package dao;

public interface userdao {
    void select();
}

有两个实现方法

package dao;

public class mysqlimpl implements userdao {
    @Override
    public void select() {
        System.out.println("mysql");
    }
}
package dao;

public class mssqlimpl implements userdao {
    @Override
    public void select() {
        System.out.println("mssql");
    }
}

我们如果要使用的话

package dao;

import org.junit.Test;

public class test1 {

    @Test
    public void withoutSpring(){
        userdao mysqldaoimpl = new mysqlimpl();
        mysqldaoimpl.select();
    }

}

就是前面概述中所说直接new了一个对象,如果在后面想换查询时还要修改代码,效率不高,而且这样写的话控制权全在开发者手里,而不是在用户的手里。

Spring使用

快速创建一个maven工程,然后添加spring依赖即可

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.5.RELEASE</version>
</dependency>

在resources下新建一个bean.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="mysqlimpl" class="dao.mysqlimpl"/>

    <bean id="mssqlimpl" class="dao.mssqlimpl"/>
    
</beans>

添加如下的test方法即可

@Test
    public void SpringTest(){
        ApplicationContext cl = new ClassPathXmlApplicationContext("Bean.xml");  //传入xml文件
        userdao mysqldaoimpl = (userdao)cl.getBean("mysqldaoimpl");  //获取mysqlimpl方法
        mysqldaoimpl.select();//调用mysqlimpl方法
    }

在这里插入图片描述

  1. 创建 ApplicationContext 对象时,我们使用了 ClassPathXmlApplicationContext 类。该类用于加载 Spring 配置文件、创建和初始化所有对象,也就是下面配置文件中提到的 Bean。
  2. ApplicationContext.getBean() 方法用来获取 Bean,该方法返回值类型为 Object,通过强制类型转换为 userdao 的实例对象,根据该对象调用类中的方法。

IoC容器

BeanFactory 容器

BeanFactory 是最简单的容器,由 org.springframework.beans.factory.BeanFactory 接口定义,采用懒加载(lazy-load),所以容器启动比较快。BeanFactory 提供了容器最基本的功能。

简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。

BeanFactory 接口有多个实现类,最常见的是 org.springframework.beans.factory.xml.XmlBeanFactory。使用 BeanFactory 需要创建 XmlBeanFactory 类的实例,通过 XmlBeanFactory 类的构造函数来传递 Resource 对象。

Resource resource = new ClassPathResource("applicationContext.xml"); 
BeanFactory factory = new XmlBeanFactory(resource); 

ApplicationContext 容器

ApplicationContext 继承了 BeanFactory 接口,由 org.springframework.context.ApplicationContext 接口定义

ApplicationContext 接口有两个常用的实现类:

ClassPathXmlApplicationContext

该类从类路径 ClassPath 中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);

在上述代码中,configLocation 参数用于指定 Spring 配置文件的名称和位置,如 Beans.xml。

FileSystemXmlApplicationContext

该类从指定的文件系统路径中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。

ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);

它与 ClassPathXmlApplicationContext 的区别是:在读取 Spring 的配置文件时,FileSystemXmlApplicationContext 不会从类路径中读取配置文件,而是通过参数指定配置文件的位置。即 FileSystemXmlApplicationContext 可以获取类路径之外的资源,如“F:/workspaces/Beans.xml”。

Bean

可以把 Spring IoC 容器看作是一个大工厂,Bean 相当于工厂的产品,如果希望这个大工厂生产和管理 Bean,则需要告诉容器需要哪些 Bean,以及需要哪种方式装配 Bean。

Bean标签作用:

属性名称描述
idBean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。
namename 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。
class该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。
scope用于设定 Bean 实例的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton
init-method容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法
constructor-arg可以使用此元素传入构造参数进行实例化

依赖注入

Spring 容器在创建被调用者的实例时,会自动将调用者需要的对象实例注入给调用者,调用者通过 Spring 容器获得被调用者实例,这称为依赖注入(Dependency Injection,DI)。我们不需要再创建示例了(New)

构造注入

使用类中的构造函数,让 spring 框架来为我们注入。

Eg:

package User;

import java.util.Date;

public class Student {

    private String name;
    private Integer age;
    private Date date;

    public Student() {
    }

    public Student(String name, Integer age, Date date) {
        this.name = name;
        this.age = age;
        this.date = date;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    @Override
    public String toString() {
        return "Perpon{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", date=" + date +
                '}';
    }

}

xml添加如下

<bean id="person" class="User.Student">

    <constructor-arg name="name" value="xiaoming"/>
    <constructor-arg name="age" value="18"/>
    <constructor-arg name="date" ref="now"/>

</bean>
<bean id = "now" class="java.util.Date"/>

即可测试

@Test
    public void DIConstrutor(){
        ApplicationContext cl = new ClassPathXmlApplicationContext("Bean.xml");  //传入xml文件
        Student person = (Student) cl.getBean("person");
        System.out.println(person);
    }

在 标签中,包含 ref、value、type、index 等属性。value 属性用于注入基本数据类型以及字符串类型的值;ref 属性用于注入已经定义好的 Bean;type 属性用来指定对应的构造函数,当构造函数有多个参数时,可以使用 index 属性指定参数的位置,index 属性值从 0 开始。

set注入

 <bean id="person" class="User.Student">

     <property name="name" value="xiaoming"/>
     <property name="age" value="18"/>
     <property name="date" ref="now"/>


</bean>
<bean id = "now" class="java.util.Date"/>

在 标签中,包含 name、ref、value 等属性。name 用于指定参数名称;value 属性用于注入基本数据类型以及字符串类型的值;ref 属性用于注入已经定义好的 Bean。

Bean自动装配

Bean 的装配可以理解为依赖关系注入,Bean 的装配方式也就是 Bean 的依赖注入方式。自动装配就是指 Spring 容器在不使用 和 标签的情况下,可以自动装配(autowire)相互协作的 Bean 之间的关联关系,将一个 Bean 注入其他 Bean 的 Property 中。

使用自动装配需要配置 元素的 autowire 属性。autowire 属性有五个值,具体说明如下表所示。

名称说明
no默认值,表示不使用自动装配,Bean 依赖必须通过 ref 元素定义。
byName根据 Property 的 name 自动装配,如果一个 Bean 的 name 和另一个 Bean 中的 Property 的 name 相同,则自动装配这个 Bean 到 Property 中。
byType根据 Property 的数据类型(Type)自动装配,如果一个 Bean 的数据类型兼容另一个 Bean 中 Property 的数据类型,则自动装配。
constructor类似于 byType,根据构造方法参数的数据类型,进行 byType 模式的自动装配。
autodetect(3.0版本不支持)如果 Bean 中有默认的构造方法,则用 constructor 模式,否则用 byType 模式。

byNameEg:

package User;

public class Student {

    private String name;
    private Play play;
    private Study study;

    public Student() {
    }

    public Student(String name, Play play, Study study) {
        this.name = name;
        this.play = play;
        this.study = study;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Study getStudy() {
        return study;
    }

    public void setStudy(Study study) {
        this.study = study;
    }

    public Play getPlay() {
        return play;
    }

    public void setPlay(Play play) {
        this.study = study;
    }

}

xml添加(XML 文件中 Bean 的 id 必须与类中的属性名称相同)

<bean id="person" class="User.Student" autowire="byName">
    <property name="name" value="xiaoming"/>
</bean>

<bean id="play" class="User.Play"/>
<bean id="study" class="User.Study"/>

测试一下

@Test
    public void byName(){
        ApplicationContext cl = new ClassPathXmlApplicationContext("Bean.xml");  //传入xml文件
        Student person = (Student) cl.getBean("person");
        System.out.println(person.getName());
        person.getPlay().method();
        person.getStudy().method();
    }

基于注解装配Bean

如果还是嫌写Bean太过麻烦,可以用注解的方式,详细用法可以见:基于注解装配Bean

Aop

AOP 的全称是“Aspect Oriented Programming”,即面向切面编程。

通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。AOP 就是代理模式的典型应用。

why

在这里插入图片描述

相关术语

横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

名称说明
Joinpoint(连接点)指那些被拦截到的点,在 Spring 中,指可以被动态代理拦截目标类的方法。
Pointcut(切入点)指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。
Advice(通知)指拦截到 Joinpoint 之后要做的事情,即对切入点增强的内容。
Target(目标)指代理的目标对象。
Weaving(植入)指把增强代码应用到目标上,生成代理对象的过程。
Proxy(代理)指生成的代理对象。
Aspect(切面)切入点和通知的结合。(也是对横切关注点的抽象)

AOP实现(AspectJ)

导入相关依赖

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
    <scope>runtime</scope>
</dependency>

接口

package AOP;

public interface service {
    void add();
    void delete();
    void update();
    void qurey();
}

实现

package AOP;

public class serviceImpl implements service {
    @Override
    public void add() {
        System.out.println("add");
    }

    @Override
    public void delete() {
        System.out.println("delete");
    }

    @Override
    public void update() {
        System.out.println("update");
    }

    @Override
    public void qurey() {
        System.out.println("query");
    }
}

不修改代码的情况下,想增强一下它的功能的话,以前会直接使用动态代理来实现,书写起来很麻烦。这里就可以使用到aop。

这里再来定义2个方法,分别是方法执行前执行的方法,和方法执行后执行的方法。也叫做前置增强和后置增强

前置:

package AOP;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class log implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println(o.getClass().getName()+"的"+method.getName()+"方法执行了");
    }
}

后置

package AOP;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;


public class afterlog implements AfterReturningAdvice{
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"执行结果为"+o);
    }
}

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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- Spring aop 命名空间-->

    <bean id="service" class="AOP.serviceImpl"/>
    <bean id="log" class="AOP.log"/>
    <bean id="afterlog" class="AOP.afterlog"/>

    <aop:config>
        <!--        声明切入点,并且使用expression表达式设置需要执行的位置-->
        <aop:pointcut id="pointcut" expression="execution(* AOP.serviceImpl.*(..))"/>
        <!--        advice-ref:设置需要切入的功能,pointcut-ref:设置需要切入的点                      -->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
    </aop:config>

</beans>

Test

@Test
    public void AOP(){
        ApplicationContext cl = new ClassPathXmlApplicationContext("Bean_Aspectj.xml");
        service s = (service) cl.getBean("service");
        s.add();
    }

在这里插入图片描述

也可以将前置增强和后置增强放到一个类中,详细示例可见:Spring AOP:基于AspectJ XML开发的示例(注意method)

参考链接

Java学习之Spring框架入门篇

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值