zoukankan      html  css  js  c++  java
  • SSM框架学习之Spring浅谈

    Spring介绍

    1、什么是Spring?

    百度:

    Spring是JavaEE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。

    补充:想要具体了解学习Spring,建议多逛逛Spring官网,不一定要全部看懂,一开始只是混个脸熟也有利于后面进一步的学习。

    2、我们常说的Spring指什么?

    如果我们打开Spring官网,打开project会发现:Spring就像是一个大的容器型框架,下面还有比较熟知的常见项目和框架,例如:Springboot,SpringCloud,SpringData等等。其中“SpringFramework”的Core technologies(核心技术),会发现一些比较常见的关键词:DI(IOC)和AOP,就是常说的控制反转和面向切面编程。所以,我们常说的“Spring”大部分情况下是指“SpringFramework”。 

    Springframework核心技术

    IOC(控制反转):

    一般程序的设计思想是从Controller/Servlet层Service层再到Dao/Mapper层,如果对某个下游的类进行更改名字,或者进行更换,则整个流程都需要进行相应的更改,所以代码的耦合性太高,牵一发而动全身,所以为了解决这个问题设计出了IOC(控制反转)的思想:把创建下游类的功能交给一个“类似工厂”(BeanFactory)的对象进行管理(工厂思想+反射)。

    1 public class MyController {
    2     public static void main(String[] args) {
    3         MyBeanFactory myBeanFactory = new MyBeanFactory();
    4         SpringDao springDao = (SpringDao) myBeanFactory.getBean();
    5         springDao.test();
    6     }
    7 
    8 }
    Controller
     1 public class MyBeanFactory {
     2     public Object getBean() {
     3         Object bean = null;
     4         try {
     5             bean = Class.forName("com.emo.dao.SpringDao").newInstance();
     6         } catch (InstantiationException e) {
     7             e.printStackTrace();
     8         } catch (IllegalAccessException e) {
     9             e.printStackTrace();
    10         } catch (ClassNotFoundException e) {
    11             e.printStackTrace();
    12         }
    13         return bean;
    14     }
    15 }
    BeanFactory
    1 public class SpringDao {
    2     public void test() {
    3         System.out.println("SpringDao被调用!");
    4     }
    5 }
    Dao

    优点:不需要每次更改Dao层数据都需要整个流程都进行更改,只需要修改BeanFactory中的“com.emo.dao.SpringDao”。

    缺点:还是需要进行手动修改代码。

    工厂思想还是需要改代码,于是在这个基础上加上配置文件(ApplicationContext.xml)进行改造,这样只需要修改配置文件基本不需要修改代码。

    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <beans xmlns="http://www.springframework.org/schema/beans"
    3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4     xsi:schemaLocation="
    5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    6 
    7     <!-- bean definitions here -->
    8     <bean id="springDao" class="com.emo.dao.SpringDao"></bean>
    9 </beans>
    ApplicationContext.xml
    public class SpringDao {
        public void test() {
            System.out.println("SpringDao被调用!");
        }
    }
    Dao
    1 public class MyController {
    2     public static void main(String[] args) {
    3         //spring配置方式,创建spring工厂,加载spring配置文件
    4          ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    5          //从spring工厂中获取对象,通过bean的id/name
    6          SpringDao springDao = (SpringDao) ac.getBean("springDao");
    7          springDao.test();
    8     }
    9 }
    Controller

    注意:记得要导入SpringFramework依赖

    1         <dependency>
    2             <groupId>org.springframework</groupId>
    3             <artifactId>spring-context</artifactId>
    4             <version>5.1.7.RELEASE</version>
    5         </dependency>

    DI(依赖注入):

    如何通过调用Service,继而调用Dao层?为了解决这个问题,就有了依赖注入,把Dao成当作Service层的“属性”或者“元素”,注入到配置文件中。

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
     6 
     7     <!-- bean definitions here -->
     8     <bean id="springDao" class="com.emo.dao.SpringDao"></bean>
     9     <bean id ="springService" class="com.emo.service.SpringService">
    10     <!-- 注入对象 -->
    11     <!-- property 根据类中的setter方法进行属性注入 -->
    12     <!-- name:setter方法的后缀小写,比如setXxx 对应的name为xxx -->
    13     <!-- ref:引用哪一个bean(对象),值为bean的id/name -->
    14     <property name="springDao" ref="springDao" />
    15 </bean>
    16     
    17 </beans>
    ApplicationContext.xml
    1 public class SpringDao {
    2     public void test() {
    3         System.out.println("SpringDao被调用!");
    4     }
    5 }
    SpringDao
     1 public class SpringService {
     2     SpringDao springDao = null;
     3 
     4     public void setSpringDao(SpringDao springDao) {
     5         this.springDao = springDao;
     6     }
     7 
     8     public void test() {
     9         System.out.println("SpringService被调用!");
    10         springDao.test();
    11     }
    12 
    13 }
    SpringService
    1 public class MyController {
    2     public static void main(String[] args) {
    3         //spring配置方式,创建spring工厂,加载spring配置文件
    4         ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
    5          //从spring工厂中获取对象,通过bean的id/name
    6          SpringService springService = (SpringService) ac.getBean("springService");
    7          springService.test();
    8     }
    9 }
    MyController

    注意:把Dao层注入到Service层时,要把Dao层当作Service层的属性或者元素,所以要在Service层提供setXxxDao()方法。

     1 public class SpringService {
     2     SpringDao springDao = null;
     3 
     4     public void setSpringDao(SpringDao springDao) {
     5         this.springDao = springDao;
     6     }
     7 
     8     public void test() {
     9         System.out.println("SpringService被调用!");
    10         springDao.test();
    11     }
    12 
    13 }

    简要总结:IOC就是由原本手动创建对象交给Spring工厂去创建对象,DI就是把一个对象A当作另一个对象B的属性或者元素注入到配置文件的B对象中。

    AOP(面向切面编程):

    AOP (Aspect Oriented Programing) 称为:面向切面编程,它是一种编程思想。AOP 是 OOP(面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构),思想延续,它是基于代理思想,对原来目标对象,创建代理对象,在不修改原对象代码情况下,通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强!

    关于代理相关资料:https://www.cnblogs.com/Bernard94/p/12358728.html

    AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码的编写方式(例如性能监视、权限管理、事务管理、安全检查、缓存、日志记录等)。

    相关术语:

    1. Aspect(切面): 是通知和切入点的结合,通知和切入点共同定义了关于切面的全部内容---它的功能、在何时和何地完成其功能
    2. joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.
    3. Pointcut(切入点):所谓切入点是指我们要对哪些joinpoint进行拦截的定义.通知定义了切面的”什么”和”何时”,切入点就定义了”何地”.
    4. Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    5. Target(目标对象):代理的目标对象
    6. weaving(织入):是指把切面应用到目标对象来创建新的代理对象的过程.切面在指定的连接点织入到目标对象
    7. Introduction(引介):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

     JDK动态代理实现AOP:

    1 public interface People {
    2     public void eat() ;
    3 }
    People
    1 public class Student implements People {
    2 
    3     public void eat() {
    4         System.out.println("吃东西!");
    5     }
    6 
    7 }
    Student
     1 public class ProxyObject {
     2     private Object target;
     3 
     4     public ProxyObject(Object target) {
     5         this.target = target;
     6     }
     7 
     8     public Object getProxyObject() {
     9         // 参数1:目标对象的类加载器
    10         // 参数2:目标对象实现的接口
    11         // 参数3:回调方法对象
    12         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
    13                 new InvocationHandler() {
    14 
    15                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    16                         // 如果是保存的方法,执行记录日志操作
    17                         if (method.getName().equals("eat")) {
    18                             ProxyEat();
    19                         }
    20                         // 目标对象原来的方法执行
    21                         Object object = method.invoke(target, args);// 调用目标对象的某个方法,并且返回目标对象方法的返回值
    22 
    23                         return object;
    24                     }
    25                 });
    26     }
    27 
    28     private void ProxyEat() {
    29         System.out.println("eat方法加强!");
    30     }
    31 }
    ProxyObject
    1 public class test {
    2     public static void main(String[] args) {
    3         Student student = new Student();
    4         ProxyObject proxyObject = new ProxyObject(student);
    5         People proxyStudenty = (People) proxyObject.getProxyObject();
    6         proxyStudenty.eat();
    7     }
    8 }
    test

    注意:因为JDK必须对接口生成代理,所以代理对象返回的是接口:People,不能是具体类:Student。

     CGLIB动态代理实现AOP:

    1 public class Dog {
    2     public void bark() {
    3         System.out.println("汪汪。。。");
    4     }
    5 }
    Dog
     1 public class ProxyObject implements MethodInterceptor {
     2     private Object target;
     3 
     4     public ProxyObject(Object target) {
     5         this.target = target;
     6     }
     7 
     8     // 获取代理对象
     9     public Object getProxyObject() {
    10         // 1.代理对象生成器(工厂思想)
    11         Enhancer enhancer = new Enhancer();
    12         // 2.在增强器上设置两个属性
    13         // 设置要生成代理对象的目标对象:生成的目标对象类型的子类型
    14         enhancer.setSuperclass(target.getClass());
    15         // 设置回调方法
    16         enhancer.setCallback(this);
    17         // Callback
    18         // 3.创建获取对象
    19         return enhancer.create();
    20     }
    21 
    22     // 回调方法(代理对象的方法)
    23     // 参数1:代理对象
    24     // 参数2:目标对象的方法对象
    25     // 参数3:目标对象的方法的参数的值
    26     // 参数4:代理对象的方法对象
    27     public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    28         // 如果是保存的方法,执行记录日志操作
    29         if (method.getName().equals("bark")) {
    30             ProxyBark();
    31         }
    32         // 目标对象原来的方法执行
    33         Object object = method.invoke(target, args);// 调用目标对象的某个方法,并且返回目标对象方法的执行结果
    34         return object;
    35     }
    36 
    37     private void ProxyBark() {
    38         System.out.println("Bark方法加强!");
    39     }
    40 
    41 }
    ProxyObject
    1 public class demo {
    2     public static void main(String[] args) {
    3         Dog dog = new Dog();
    4         ProxyObject proxyObject = new ProxyObject(dog);
    5         Dog proxyDog = (Dog) proxyObject.getProxyObject();
    6         proxyDog.bark();
    7     }
    8 }
    demo

    注意:Cglib要实现“MethodInterceptor”接口,此接口在SpringFramework中,所以要引入spring-context依赖:

    1         <dependency>
    2             <groupId>org.springframework</groupId>
    3             <artifactId>spring-context</artifactId>
    4             <version>5.1.7.RELEASE</version>
    5         </dependency>

    总结:

    • Jdk代理:基于接口的代理,一定是基于接口,会生成目标对象的接口类型的子对象。
    • Cglib代理:基于类的代理,不需要基于接口,会生成目标对象类型的子对象。
  • 相关阅读:
    POJ1606 Jugs
    NYOJ148 fibonacci数列(二)
    NYOJ 82 迷宫寻宝(一)
    POJ1579 Function Run Fun
    NYOJ21 三个水杯
    [WorldWind学习]16.Lod技术(1)
    统计推断和统计决策
    程序员,有点累!
    [WorldWind学习]17.视域调度(视域体裁剪)
    c#调用非托管代码
  • 原文地址:https://www.cnblogs.com/Bernard94/p/14092892.html
Copyright © 2011-2022 走看看