Spring基础知识整理

image

1. spring 组件

image

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。

Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称为 Bean。

Core 核心模块:提供了 Spring 框架的基本组成部分,包括 IoC 和 DI 功能。

Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。

Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。

2. spring

2.1 IOC

概述

一句话:创建对象交给容器

通过容器去获取对象

image

image

2.2 IOC底层原理

1 XML解析技术读取配置文件

<bean id="empDao" class="com.msb.dao.impl.EmpDaoImpl"></bean>

2 反射技术实例化对象,放到容器中

获得类的字节码

​                  Class clazz =Class.forName("com.msb.dao.impl.EmpDaoImpl")

​      通过字节码实例化对象

​      Object obj  = clazz.newInstance();

​                        将对象放到一个map集合中

​     map.put("empDao",obj)

3工厂模式返回Bean对象 getBean方法


IOC接口

   BeanFactory            接口: IOC容器基本功能接口,是spring内部使用的接口,我们在处理业务时一般不直接使用该接口

   ApplicationContext 接口: BeanFactory的子接口,提供更多更强大的功能,研发人员一般使用的接口

2.3 注解方式创建对象IOC

第一步:在applicationContext.xml中配置开启注解扫描

第二步:在类上添加注解,让spring容器给我们创建bean实例并存储于容器中

组件扫描配置注解识别

3. AOP

3.1 jdk 的动态代理

image

package cn.hba.modules.bootstrap.mq;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
 * @Author: Ma HaiYang
 * @Description: MircoMessage:Mark_7001
 */
public class Test1 {
    public static void main(String[] args) {
        Dinner dinner=new Person("张三");
        // 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
//        ClassLoader loader,被代理的对象的类加载器
        ClassLoader classLoader = dinner.getClass().getClassLoader();
//        Class<?>[] interfaces,被代理对象所实现的所有接口
        Class[] interaces= dinner.getClass().getInterfaces();
//        InvocationHandler h,执行处理器对象,专门用于定义增强的规则
        InvocationHandler handler = new InvocationHandler(){
            // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                Object proxy, 代理对象
//                Method method,被代理的方法
//                Object[] args,被代理方法运行时的实参
                Object res=null;
               if(method.getName().equals("eat")){
                   System.out.println("饭前洗手");
                   // 让原有的eat的方法去运行
                   res =method.invoke(dinner, args);
                   System.out.println("饭后刷碗");
               }else{
                   // 如果是其他方法,那么正常执行就可以了
                   res =method.invoke(dinner, args);
               }
                return res;
            }
        };
        Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
        dinnerProxy.eat("包子");
        //dinnerProxy.drink();
    }
}
interface Dinner{
    void eat(String foodName);
    void drink();
}
class Person implements Dinner{
    private String name;
    public Person(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝茶");
    }
}
class Student implements Dinner{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在食堂吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝可乐");
    }
}

3.2 cjlib的动态代理

image

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * @Author: Ma HaiYang
 * @Description: MircoMessage:Mark_7001
 */
public class Test1 {
    @Test
    public void testCglib(){
        Person person =new Person();
        // 获取一个Person的代理对象
        // 1 获得一个Enhancer对象
        Enhancer enhancer=new Enhancer();
        // 2 设置父类字节码
        enhancer.setSuperclass(person.getClass());
        // 3 获取MethodIntercepter对象 用于定义增强规则
        MethodInterceptor methodInterceptor=new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                /*Object o,  生成之后的代理对象 personProxy
                Method method,  父类中原本要执行的方法  Person>>> eat()
                Object[] objects, 方法在调用时传入的实参数组
                MethodProxy methodProxy  子类中重写父类的方法 personProxy >>> eat()
                */
                Object res =null;
                if(method.getName().equals("eat")){
                    // 如果是eat方法 则增强并运行
                    System.out.println("饭前洗手");
                    res=methodProxy.invokeSuper(o,objects);
                    System.out.println("饭后刷碗");
                }else{
                    // 如果是其他方法 不增强运行
                    res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
                }
                return res;
            }
        };
        // 4 设置methodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5 获得代理对象
        Person personProxy = (Person)enhancer.create();
        // 6 使用代理对象完成功能
        personProxy.eat("包子");
    }
}
class Person  {
    public Person( ) {
    }
    public void eat(String foodName) {
        System.out.println("张三正在吃"+foodName);
    }
}

3.3 总结

1. 使用静态代理,每一个代理,都要写一个代理对象
2. 静态代理,就是在原有的类外面在套一个代理类,增强原有的类的功能
3. 一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现 日志处理,权限控制,性能检测,事务控制等
4. AOP实现的原理就是动态代理,在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理

3. 4 spring 中使用AOP

  1. 定义切点

image

  1. 配置类

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    @Configuration
    @ComponentScan(basePackages = "com.msb")
    @EnableAspectJAutoProxy(proxyTargetClass = true)
    public class SpringConfig {
    }
    
    
  2. 写切面类

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    import java.util.Arrays;
    /**
     * @Author: Ma HaiYang
     * @Description: MircoMessage:Mark_7001
     */
    @Component
    @Aspect
    public class DaoAspect {
        //定义公共切点
        @Pointcut("execution(* com.msb.dao.*.add*(..))")
        public void addPointCut(){}
        /*
        * 前置通知: 切点方法执行之前先执行的功能
        * 参数列表可以用JoinPoint接收切点对象
        * 可以获取方法执行的参数
        * */
        @Before("addPointCut()")
        public void methodBefore(JoinPoint joinPoint){
            System.out.println("Before invoked");
        }
        /*
        * 后置通知:方法执行之后要增强的功能
        * 无论切点方法是否出现异常都会执行的方法
        * 参数列表可以用JoinPoint接收切点对象
        * */
        @After("addPointCut()")
        public void methodAfter(JoinPoint joinPoint){
            System.out.println("After invoked");
        }
        /*
         * 返回通知:切点方法正常运行结束后增强的功能
         * 如果方法运行过程中出现异常,则该功能不运行
         * 参数列表可以用 JoinPoint joinPoint接收切点对象
         * 可以用Object res接收方法返回值,需要用returning指定返回值名称
         * */
        @AfterReturning( value = "addPointCut()",returning = "res")
        public void methodAfterReturning(JoinPoint joinPoint,Object res){
            System.out.println("AfterReturning invoked");
        }
        /*
         * 异常通知:切点方法出现异常时运行的增强功能
         * 如果方法运行没有出现异常,则该功能不运行
         * 参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称
         * */
        @AfterThrowing( value = "addPointCut()",throwing = "ex")
        public void methodAfterThrowing(Exception ex){
            System.out.println("AfterThrowing invoked");
        }
        /*环绕通知:在切点方法之前和之后都进行功能的增强
        * 需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能
        * 方法列表可以通过ProceedingJoinPoint获取执行的切点
        * 通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置
        * proceedingJoinPoint.proceed()方法会将切点方法的返回值获取到,并交给我们,可以做后续处理
        * 我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值
        * */
        @Around("addPointCut()")
        public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            System.out.println("aroundA invoked");
            Object proceed = proceedingJoinPoint.proceed();
            System.out.println("aroundB invoked");
            return proceed;
        }
    }
    

4. bean的生命周期

1 通过构造器创建bean实例 执行构造器

2 为bean属性赋值 执行set方法

3 初始化bean 调用bean的初始化方法,需要配置指定调用的方法

4 bean的获取 容器对象 getBean方法

5 容器关闭销毁bean 调用销毁方法,需要配置指定调用的方法

5. bean自动装配

一个类里面包含其他类的对象,实用@autowire 或者@Resouce

*
@Autowired
* 根据类型到容器中去寻找对应的对象,找到后给当前属性赋值
* 不需要依赖 set方法
* 属性类型可以是接口,会自动匹配对应的实现类对象
* @Autowired配合 @Qualifier,可以通过名称指定注入的对象
*
* @Resource 如果不配置name 那么就是根据类型注入
* @Resource(name="userDaoImplB") 配置name,就是根据名称注入
*
*
* @Resource  是JDK中javax包的注解
* @Autowired 和 @Qualifier 是spring中的注解
*
* @Value 可以个普通属性赋值
* @Value 可以使用${}这种表达式获取系统的变量值
*        或者是.properties属性配置文件中的值
*

6. 使用外部文件

这个是spring 的获取外部文件,springboot 使用约定的方式无需指定配置文件的位置

image

3. SpringMVC

image

常用注解

1、@RequestMapping

2. @RequestParam

3、@PathVariable

4、@RequestHeader(了解)

5、@CookieValue(了解)

1、@RequestMapping
作用:
                用于建立请求 URL 和处理请求方法之间的对应关系
出现位置:
                类上:    请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头
                方法上: 请求 URL 的第二级访问目录
属性:
   value:用于指定请求的 URL。它和 path 属性的作用是一样的。
   method:用于指定请求的方式。
   params(了解):用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。
   headers(了解):用于指定限制请求消息头的条件。

2 @RequestParam

作用:

把请求中指定名称的参数给控制器中的形参赋值。

属性:

value:请求参数中的名称。

required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。

@RequestMapping("/getRequestParam") 
public String getRequestParam(@RequestParam("name")String uname, @RequestParam(value="age",required=false)Integer age){ 
    System.out.println(username+","+age); 
    return "success"; 
}


3、@PathVariable

Restful的简介 :

REST(英文:Representational State Transfer,简称 REST)restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

restful 的优点

它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

作用:

用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

属性:

value:用于指定 url 中占位符名称。

required:是否必须提供占位符。

@Controller
public class PathController {
    @RequestMapping("/testPathVariable/{id}/{username}")
    public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("username") String username){
        System.out.println("id:"+id);
        System.out.println("username:"+username);
        System.out.println("testPathVariable1");
        return "success";
    }
}


4、@RequestHeader(了解)

作用:

用于获取请求消息头。

属性:

value:提供消息头名称

required:是否必须有此消息头 


@RequestMapping("/getRequestHeader") 
public String getRequestHeader(@RequestHeader(value="Accept", required=false)String requestHeader){ 
    System.out.println(requestHeader); 
    return "success"; 
}

5、@CookieValue(了解)

作用:

用于把指定 cookie 名称的值传入控制器方法参数。

属性:

value:指定 cookie 的名称。

required:是否必须有此 cookie

实现

@RequestMapping("/getCookie") 
public String getCookie(@CookieValue(value="JSESSIONID",required=false) String cookieValue){ 
    System.out.println(cookieValue); 
    return "success"; 
}

4.0 SpringBoot

PageHelp实现原理

PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的。内部流程是ThreadLocal中设置了分页参数(pageIndex,pageSize),之后在查询执行的时候,获取当线程中的分页参数,执行查询的时候通过拦截器在sql语句中添加分页参数,之后实现分页查询,查询结束后在 finally 语句中清除ThreadLocal中的查询参数

PageHelp使用方法

1.调用PageHelper方法:PageHelper.startPage(pageNum, pageSize)
2. MyBatis 查询方法
注意:只要你可以保证在PageHelper方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为PageHelper在finally代码段中自动清除了ThreadLocal存储的对象。

拦截器和过滤器的区别

1拦截器SpringMVC的,而过滤器是servlet的。
2拦截器不依赖与servlet容器,由spring容器初始化,过滤器依赖与servlet容器,由servlet容器初始化。
3拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。

1. 新建拦截器类。

新建拦截器类。
注意:不要忘记类上注解@Component


 @Component
public class DemoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行拦截器");
        return true;
    }
}


2. 配置拦截器

注意:类上有注解@Configuration。此类相当于SpringMVC配置文件。
addPathPattern(): 拦截哪些URL。 /
拦截全部
excludePathPatterns(): 不拦截哪些URL。当和addPathPattern()冲突时,excludePathPatterns()生效。

 @Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    private DemoInterceptor demoInterceptor;
    //配置拦截器的映射
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(demoInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
    }
}
posted @ 2021-06-17 18:52  庭有奇树  阅读(295)  评论(0编辑  收藏  举报