Spring框架

目录

Spring概述

IoC(控制反转)

如何使用IoC

配置文件

IoC底层原理

给bean注入集合

scope的作用域

Spring的继承

 Spring的依赖

 Spring的p命名空间

 Spring的工厂方法

IoC自动装载(Autowrite)

 AOP(Aspect Oriented Programming 面向切面编程)

AOP的优点:

如何使用

Spring框架两大核心机制

  • IoC(控制反转)/DI(依赖注入)
  • AOP(面向切面编 程)

Spring概述

Spring是一个企业级的开发框架,是软件设计层面的框架,是软件设计层面的,可以将应用程序进行分层,以至于开发者可以自主选择组件:

MVC:这一层可以选择Struts2、Spring、SpringMVC框架

ORMapping:这一层 库这一层可以选择Hibernate、MyBatis、Spring Data  

 优点

  • 底侵入式设计
  • 独立于各种应用服务器
  • 依赖注入特性将组件关系透明化,降低耦合度
  • 面向切面编程特性允许将通用任务进行集中式处理
  • 与第三方框架良好 整合

IoC(控制反转)

 

如何使用IoC

  • 创建Maven工程,pom.xml添加依赖
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>aispringioc</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.11.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.8</version>
            </dependency>
        </dependencies>
    
    </project>
  • 创建实体类Student
package com.xiaoming.entity;

import lombok.Data;

@Data
public class Student {
    private long id;
    private String name;
    private int age;

}
  • 传统开发方式,手动new Student
package com.xiaoming.test;

import com.xiaoming.entity.Student;

public class Test {

    public static void main(String[] args) {
        Student student = new Student();
        student.setAge(10);
        student.setId(001);
        student.setName("小明");
        System.out.println(student);

    }
}
  • 通过IoC创建对象,配置文件中添加需要管理的对象,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="student" class="com.xiaoming.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="22"></property>
    </bean>

</beans>

从IoC中获取对象

package com.xiaoming.test;

import com.xiaoming.entity.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

    public static void main(String[] args) {
//        Student student = new Student();
//        student.setAge(10);
//        student.setId(001);
//        student.setName("小明");

        //加载配置文件
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //applicationContext就相当于ioc了,从这个对象就可以取出刚刚配置的student对象了
        Student student = (Student) applicationContext.getBean("student");
        System.out.println(student);

    }
}

配置文件

  • 通过配置bean标签来完成对象的管理;
    • 其中id代表对象名;
    • clss是对象的模板类(所有交给IoC容器管理的类必须有无参构造函数)
  • 对象成员变量通过property标签完成赋值。
    • name:成员变量名。
    • value:成员变量值(基本数据类型,String可以直接赋值,如果是其他引用类型,不能通过value赋值)
    • ref:将IoC中的另外一个bean赋给当前成员变量(DI)。
      <?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="student" class="com.xiaoming.entity.Student">
              <property name="id" value="1"></property>
              <property name="name" value="张三"></property>
              <property name="age" value="22"></property>
              <property name="address" ref="address"></property>
          </bean>
          <bean id="address" class="com.xiaoming.entity.Address">
              <property name="id" value="1"></property>
              <property name="value" value="科技路"></property>
          </bean>
      
      </beans>

IoC底层原理

  • 读取配置文件,解析XML
  • 通过反射机制来实例化配置文件中所配置的所有的bean

给bean注入集合

<bean id="student" class="com.xiaoming.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="张三"></property>
        <property name="age" value="22"></property>
        <property name="address" >
            <list>
                <ref bean="address1"></ref>
                <ref bean="address2"></ref>
            </list>
        </property>
    </bean>
    <bean id="address1" class="com.xiaoming.entity.Address">
        <property name="id" value="1"></property>
        <property name="value" value="科技路"></property>
    </bean>
    <bean id="address2" class="com.xiaoming.entity.Address">
        <property name="id" value="2"></property>
        <property name="value" value="创新路"></property>
    </bean>

scope的作用域

Spring管理的bean是根据scope来生成的,表示bean的作用域,共四种。默认是单例(singleton)

  • singleton:单例,表示通过Spring容器(IoC)获取的bean是唯一的
  • prototype:原型,表示通过Spring容器(IoC)获取的bean是不同的
  • request:请求,表示在一次HTTP请求内有效
  • session:回话,表示在一个用户会话内有效

request和session只适用于Web项目,大多数情况下,使用单例和原型较多。

prototype模式当业务代码获取IoC容器中的bean时,Spring才去调用无参构造创建对应bean

singleton模式无论业务代码是否获取IoC容器中的bean,Spring在加载Spring.xml时就会创建bean

Spring的继承

与Java的继承不同,Java是类层面的继承,子类可以继承父类的内部结构;

Spring是对象层面的继承,子对象可以继承父对象的属性值。 即不同的两个类实例化对象可以完成继承,前提是子对象必须包含父对象的所有属性,同时可以在这个基础上添加其他属性。

没有继承之前

 在spring中加parent的继承

 

 Spring的依赖

与继承类似,依赖也是描述bean和bean之间的一种关系,配置依赖之后,被依赖的bean一定先创建,再创建依赖的bean,如A依赖B,先创建B,再创建A。

<bean id="student" class="com.xiaoming.entity.Student" depends-on="user"></bean>
    <bean id="user" class="com.xiaoming.entity.User"></bean>

 Spring的p命名空间

p命名空间是对IoC/DI的简化操作,使用p命名空间可以更加方便的完成bean的配置以及bean的依赖注入

 Spring的工厂方法

IoC通过工厂模式创建bean的方式有两种:

  • 静态工厂模式

实例类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
    private long id;
    private String name;
}

静态工厂方法

public class StaticCarFactory {
    private static Map<Long, Car> carMap;
    static {
        carMap = new HashMap<Long,Car>();
        carMap.put(1L,new Car(1L,"宝马"));
        carMap.put(2L,new Car(2L,"奔驰 "));
    }
    public static Car getCar(long id){
        return carMap.get(id);
    }
}

配置文件spring-factory.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">

    <!-- 配置静态工厂创建Car -->
    <bean id="car1" class="com.xiaoming.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="1"></constructor-arg>
    </bean>
</beans>
  • 实例工厂模式

实例工厂方法

package com.xiaoming.factory;

import com.xiaoming.entity.Car;

import java.util.HashMap;
import java.util.Map;

public class InstanceCarFactory {
    private Map<Long, Car> carMap;
    public InstanceCarFactory(){
        carMap = new HashMap<Long,Car>();
        carMap.put(1L,new Car(1L,"奔驰"));
        carMap.put(2L,new Car(2L,"宝马"));

    }

    public Car getCar(long id){
        return carMap.get(id);
    }
}
<!--  配置实例工厂bean -->
    <bean id="carFactory" class="com.xiaoming.factory.InstanceCarFactory"></bean>
<!--    配置实例工厂创建car-->
    <bean id="car2"  factory-bean="carFactory" factory-method="getCar">
        <constructor-arg value="1"></constructor-arg>
    </bean>

IoC自动装载(Autowrite)

IoC负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时Spring提供了另外一种更加简便的依赖注入方式:自动装载,不需要手动配置property,IoC容器会自动选择bean完成注入。

自动装载有两种方式:

  • byName:通过属性名自动装载

  • byType:通过属性的数据类型自动装载


 AOP(Aspect Oriented Programming 面向切面编程)

AOP是对面向对象编程的一个补充,在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面编程。将不同方法的同一个位置抽象成一个切面对象,对该切面对象进行编程就是AOP。

AOP的优点:

  • 降低模块之间的耦合度
  • 使系统更容易扩展
  • 更好的代码复用
  • 非业务代码更加集中,不分散,便于同一管理
  • 业务代码更加简洁纯粹,不掺杂其他代码影响

如何使用

创建maven工程,在pom.xml添加相关代码

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.11.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.0.11.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.0.11.RELEASE</version>
        </dependency>
    </dependencies>

例子:

定义计算器接口,实现加减乘除

package com.xiaoming.utils;

public interface Cal {
    public int add(int num1,int num2);
    public int sub(int num1,int num2);
    public int mul(int num1,int num2);
    public int div(int num1,int num2);
}

创建接口实现类

package com.xiaoming.utils.impl;

import com.xiaoming.utils.Cal;

public class CalImpl implements Cal {
    @Override
    public int add(int num1, int num2) {
        System.out.println("add方法参数是["+num1+","+num2+"]");
        int result = num1 + num2;
        System.out.println("add方法的结果是"+result);
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        System.out.println("sub方法参数是["+num1+","+num2+"]");
        int result = num1 - num2;
        System.out.println("sub方法的结果是"+result);
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        System.out.println("mul方法参数是["+num1+","+num2+"]");
        int result = num1 * num2;
        System.out.println("mul方法的结果是"+result);
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        System.out.println("div方法参数是["+num1+","+num2+"]");
        int result = num1/num2;
        System.out.println("div方法的结果是"+result);
        return result;
    }
}

上述代码中,日志信息和业务逻辑的耦合性高,不利于系统的维护,使用AOP可以进行AOP进行优化,使用动态代理的方式实现。

给业务代码找个代理,打印日志信息的工作交给代理来做,这样的话业务代码只需要关注自身业务即可。

package com.xiaoming.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 此类是帮助我们创建动态代理类的类
 */
public class MyInvocationHandler implements InvocationHandler {
   //接受委托对象
    private Object object = null;

    //返回代理对象
    public Object bind(Object object){
        this.object = object;
        //获取动态代理的对象
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"方法参数是["+ Arrays.toString(args) +"]");
        //业务
        Object result = method.invoke(this.object,args);
        System.out.println(method.getName()+"方法的结果是"+result);  
        return result;
    }
}
package com.xiaoming.test;


import com.xiaoming.utils.Cal;
import com.xiaoming.utils.MyInvocationHandler;
import com.xiaoming.utils.impl.CalImpl;

public class Test {
    public static void main(String[] args) {
//        Cal cal = new CalImpl();
//        cal.add(1,1);
//        cal.sub(2,1);
//        cal.mul(2,3);
//        cal.div(4,2);
        
        CalImpl cal = new CalImpl();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Cal cal1 = (Cal)myInvocationHandler.bind(cal);
        cal1.add(1,1);
        cal1.sub(2,1);
        cal1.mul(2,3);
        cal1.div(4,2);
    }
}

以上是通过动态代理实现AOP的过程,比较复杂,不好便于理解 。

Spring框架对于AOP进行封装,使Spring框架可以用面向对象的思想实现AOP。

Spring框架中不需要创建InvocationHandler,只需要创建一个切面对象,将所有的非业务代码在切面对象中完成即可,Spring框架底层会自动根据切面类即目标类生成代理对象。

LoggerAspect
 

package com.xiaoming.aop;

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


import java.util.Arrays;
//Component注解相当于将该对象配置了一个bean
//Aspect注解说将其变成切面对象
@Aspect
@Component
public class LoggerAspect {
    //*代表所有的方法,然后(..)代表参数
    @Before(value = "execution(public int com.xiaoming.utils.impl.CalImpl.* (..))")
    public void before(JoinPoint joinPoint) {
        //获取⽅方法名
        String name = joinPoint.getSignature().getName();
        //获取参数
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name + "⽅方法的参数是:" + args);
    }

    @After(value = "execution(public int com.xiaoming.utils.impl.CalImpl.* (..))")
    public void after(JoinPoint joinPoint) {
        //获取⽅方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "⽅方法执⾏行行完毕");
    }

    @AfterReturning(value = "execution(public int com.xiaoming.utils.impl.CalImpl.*(..))",returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        //获取⽅方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "⽅方法的结果是" + result);
    }

    @AfterThrowing(value = "execution(public int com.xiaoming.utils.impl.CalImpl.*(..))",throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Exception exception) {
        //获取⽅方法名
        String name = joinPoint.getSignature().getName();
        System.out.println(name + "⽅方法抛出异常:" + exception);
    }
}

LoggerAspect 类定义处添加的两个注解:
@Aspect :表示该类是切⾯面类。
@Component :将该类的对象注⼊入到 IoC 容器器。
具体⽅方法处添加的注解:
@Before :表示⽅方法执⾏行行的具体位置和时机。


CalImpl 也需要添加 @Component ,交给 IoC 容器器来管理理。

package com.xiaoming.utils.impl;

import com.xiaoming.utils.Cal;
import org.springframework.stereotype.Component;

@Component
public class CalImpl implements Cal {
    @Override
    public int add(int num1, int num2) {
        int result = num1 + num2;
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        int result = num1 - num2;
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = num1/num2;
        return result;
    }
}

spring.xml 中配置 AOP。

 

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
<!--自动扫面-->
    <context:component-scan base-package="com.xiaoming"></context:component-scan>
        <!--Aspect注解生效 为目标类自动生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>


context:component-scan 将 com.xiaoming 包中的所有类进⾏行行扫描,如果该类同时添加了了
@Component ,则将该类扫描到 IoC 容器器中,即 IoC 管理理它的对象。


aop:aspectj-autoproxy 让 Spring 框架结合切⾯面类和⽬目标类⾃自动⽣生成动态代理理对象。

测试:

package com.xiaoming.test;

import com.xiaoming.utils.Cal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
        //获取代理对象(因为Spring框架会自动生成代理对象,)
        Cal proxy = (Cal) applicationContext.getBean("test");
        proxy.add(1,1);
        proxy.sub(2,1);
        proxy.mul(2,2);
        proxy.div(3,0);
    }
}
  • 切⾯面:横切关注点被模块化的抽象对象。
  • 通知:切⾯面对象完成的⼯工作。
  • ⽬目标:被通知的对象,即被横切的对象。
  • 代理理:切⾯面、通知、⽬目标混合之后的对象。
  • 连接点:通知要插⼊入业务代码的具体位置。
  • 切点:AOP 通过切点定位到连接点

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值