Spring基础知识整理
1. spring 组件
Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 Expression Language 表达式语言模块组成,具体介绍如下。
Beans 模块:提供了 BeanFactory,是工厂模式的经典实现,Spring 将管理对象称为 Bean。
Core 核心模块:提供了 Spring 框架的基本组成部分,包括 IoC 和 DI 功能。
Context 上下文模块:建立在核心和 Beans 模块的基础之上,它是访问定义和配置任何对象的媒介。ApplicationContext 接口是上下文模块的焦点。
Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。
2. spring
2.1 IOC
概述
一句话:创建对象交给容器
通过容器去获取对象
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 的动态代理
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的动态代理
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
-
定义切点
-
配置类
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 { }
-
写切面类
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 使用约定的方式无需指定配置文件的位置
3. SpringMVC
常用注解
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");
}
}