20210727 spring笔记

本文详细介绍了Spring框架的基础概念,包括IOC、DI的基本原理,以及Bean的管理与属性注入方式。同时深入探讨了AOP面向切面编程的概念、术语及其实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring

Spring入门:

IOC(Inversion of Control)底层实现原理:

在这里插入图片描述

将原本在程序中手动创建对象的权力交给spring

DI(DI—Dependency Injection)

依赖注入spring在创建对象的过程中,将这个对象所拥有的属性注入进去。

SpringBean管理

  • spring工厂类
  • SpringBean管理(XML方式)
  • Spring的属性注入(XML方式)
  • SpringBean管理(注解方式)
  • Spring的属性注入(注解方式)

Spring 工厂类:ApplicationContext()

结构:

在这里插入图片描述

ClassPathXmlApplicationContext:加载类路径下的配置文件

FileSystemXmlApplicationContext:加载文件系统中的配置文件

1. 工厂类 BeanFactory 和 ApplicationContext 的区别。
  1. ApplicationContext 是 BeanFactory 的子接口,提供了比父接口更多的功能。

  2. 在生成 bean 实例的时候,生成的时机是不一样的。

    BeanFactory 在工厂实例化后,在调用 getBean 时创建实例。

    ApplicationContext 在一加载配置文件的时候,将配置文件中所有单例模式生成的类全部实例化。

现在一般使用 ApplicationContext,不建议使用 BeanFactory。

在这里插入图片描述

SpringBean管理(XML方式)

Bean实例化的三种方式:
  • 使用类的构造器实例化(默认无参构造)

  • 使用静态工厂方法实例化(简单工厂模式)

  • 使用实例工厂方法实例化(工厂方法模式)

Bean的常用配置:
id和name:

一般情况下在装配一个Bean时,通过指定一个id属性作为Bean的名称。

id属性在ioc容器中必须是唯一的。

如果Bean名称 中有特殊字符,就要使用name属性。

class:

用于设置一个类的全路径,主要作用是IOC容器生成类的实例。

Bean的作用域:scope

在这里插入图片描述

Bean的生命周期:
init-method和destory-method属性:

在这里插入图片描述

Bean的完整生命周期:

在这里插入图片描述

BeanProcessor:

Spring属性注入;

  • 构造方法注入 --spring支持

  • setter方法注入 --spring支持(实际开发中更习惯于用)

  • p名称空间注入 --spring2.5以后引入的

  • 接口注入

  • SpEL(Spring expression language,spring表达式语言)注入

<bean id ="" value=" #{表达式}">

SpEL表达式:语法#{}

#{‘hello'} --使用字符串

#{beanId} --使用另一个bean

#{beanId.connect.toUpperCase()} --使用指定名属性,并使用方法

#{T(java.lang.Math).PI} --使用静态字段或方法

复杂类型的属性注入
  • 数组类型的注入

  • List集合类型的属性注入

  • Set类型的属性注入

  • Map类型的属性注入

  • properties类型注入

SpringBean管理(注解方式)

实例化Bean有四个注解

@Component

@Repository --持久层

@Service --业务层

@Colltroller --WEB层

bean的作用域配置

Spring中可以使用scope属性来配置bean的作用域:
  singleton:单例,在初始化配置文件时生成单例bean对象
  prototype:原型的,在初始化配置文件时不生成bean对象,使用时返回不同的bean对象
  request:web环境下每一个request请求都会返回一个不同的bean,只在本次请求中有效
  session:web环境下每一个request请求都会返回一个不同的bean,在session中有效

属性(对象)注入(注解方式)
@value

简单属性注入:有setter()需要将@value注解放在setter()方法上;无setter()放在属性上。

@AutoWired

自动注入:默认按照类型注入;

—如果两个相同类型Bean的类型是在相同的,则按名称注入

@Autowired注入时可以针对成员变量或set方法

–通过@Autowired和@Required属性,设置一定要找到匹配的Bean

–使用Qualifier指定注入Bean的名称

@Resource:@AutoWired+@Qualifier
其他注解

@PostContruct:相当于init-method

@PreDestroy:相当于destory-method(只在@scope为singleton时可以使用)

@scope:相当于xml中的scope

xml配置和注解配置混合使用:

xml方式的优点–结构清晰,易于阅读。

注解方式有点–开发边界,属性注入方便。

xml与注解混合开发:

1、引入context命名空间

2、在配置文件中添加context:annotation-condig标签

Spring的AOP

AOP概述

AOP面向切面编程

采用横向抽取机制,取代了纵向继承体系重复性的代码(性能监视、事务管理、安全检查、缓存)。

使用纯java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强代码。

public class UserDaoImpl implement UserDao{

	public void save(){
    checkPrivilege();
	//保存
	}

	public void update(){
	//修改
	}

	public void delete(){
	//删除
	}

	public void find(){
	//查找
	}
    public void checkPrivilege(){
	//权限校验
    }

}

纵向继承:

public class BaseDaoImpl {
  public void checkPrivilege(){
	//权限校验
    }
}
public class UserDaoImpl extends BaseDaoImpl{
   public void save(){
    checkPrivilege();
	//保存
	} 

}

采用横向抽取(代理机制),取代纵向继承:

实现save()的增强。

public class UserDaoImpl implement UserDao{
    public void save(){
	//保存
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdGt9Nce-1631933686883)(C:\Users\zhangyn\AppData\Roaming\Typora\typora-user-images\image-20210726162450149.png)]

AOP的相关术语:

Joinpoint(连接点):可以被拦截到的点,spring只支持方法连接点,方法有关的前前后后(抛出异常),都是连接点。

​ *可以被增强的方法:下述代码的增删改查方法为连接点。

Pointcut(切入点):指的是真正被拦截到的点。

​ *只想对save方法进行增强,save方法称为切入点。

Adivce(通知):拦截后要做的事情。(方法层)

​ *对save方法要进行权限校验,权限校验的方法被称为通知。

Introduction(引介):动态在类上添加新的方法和属性。(类层面Spring不考虑)

Target(目标):被增强的对象。

​ *UserDaoImpl是目标。

Weaving(织入):将Adivce(通知)应用到Target(目标)的过程称为织入。

​ *将权限校验应用到UserDaoImpl的save方法的过程称为织入。

Proxy(代理):应用了增强后会产生代理对象。

Aspect(切面):切入点和通知的组合。(可由多个切入点和通知组合)

public class UserDaoImpl implement UserDao{

	public void save(User user){
    checkPrivilege();
	//保存
	}

	public void update(User user){
	//修改
	}

	public void delete(User user){
	//删除
	}

	public void find(){
	//查找
	}

}

AOP的底层实现(无需手写,可通过配置文件实现)

JDK动态代理(对实现接口的类进行动态代理)

​ Proxy.newProxyInstance:
​ 第一个参数:类的加载器
​ 第二个参数:类实现的接口
​ 第三个参数:InvocationHandler接口的实例

public class UserDaoImpl implement UserDao{

	public void save(User user){
    
	//保存前需要加权限校验
	}

	public void update(User user){
	//修改
	}

	public void delete(User user){
	//删除
	}

	public void find(){
	//查找
	}

}
public class MyJdkProxy implements InvocationHandler{
	//传入需要增强的类
    public UserDao userDao;
    
    public MyJdkProxy(UserDao userDao){
        this.userDao=userDao;
    }
    
    public Object creatProxy(){
        /*newProxyInstance:
        	第一个参数:类的加载器
        	第二个参数:类实现的接口
        	第三个参数:InvocationHandler接口的实例
        */
        Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this)
            return proxy;
    }
    public Object invoke(Object proxy,Method method,Object args[]) throws Throwable{
        if ("save".equals(method.getName()){
            System.out.println("权限校验");
    }
            return method.invoke(userDao,args);
}
public class Test{
	@Test
	public void demo1(){
	UserDao userDao = new UserDaoImpl();
	UserDao proxy = (UserDao)new MyJdkProxy(userDao).creatProxy();
	proxy.save();
	}
}
使用CGLIB生成代理(对没有实现接口的类进行动态代理)

​ 1、创建核心类
​ 2、设置父类
​ 3、设置回调
​ 4、生成代理

public class UserDaoImpl implement UserDao{	public void save(User user){    	//保存前需要加权限校验	}	public void update(User user){	//修改	}	public void delete(User user){	//删除	}	public void find(){	//查找	}}
public class MyCGLIB implements MethodInterceptor{	//传入需要增强的类    public UserDao userDao;        public MyJdkProxy(UserDao userDao){        this.userDao=userDao;    }        public Object creatProxy(){               //1、创建核心类        Enhancer enhancer = new Enhancer();        //2、设置父类        enhancer.setSupperclass(userDao.getClass());        //3、设置回调        enhancer.setCallback(this);        //4、生成代理        Object proxy = enhancer.create();            }    public Object intercept(Object proxy,Method method,Object [] args,MethodProxy methodProxy) throws Throwable{        if ("save".equals(method.getName()){            System.out.println("权限校验");    }            //返回当前代理类的父类(即UserDao)和参数列表            return methodProcxy.invokeSuper(proxy,args);}
代理知识总结:
  • 程序中应优先对接口创建代理,便于程序维护。

  • 标记为final的方法不能产生代理。

    –JKD动态代理是针对接口生成子类,接口中方法不能用final修饰

    –CGLIB是针对目前类产生子类,因此类和方法不能是final

  • spring只能对方法进行增强。

Spring传统AOP

Spring传统AOP的通知类型

前置通知:org.springframework.aop.MethodBeforeAdvice

​ 在目标方法执行前实施增强。

后置通知:org.springframework.aop.AfterReturningAdvice

​ 在目标方法执行后实施增强。

环绕通知:org.springframework.aop.MethodTnterceptor

​ 在目标方法执行前后实施增强。

异常抛出通知:org.springframework.aop.ThrowsAdvice

​ 在目标方法抛出异常后实施增强。

Spring传统AOP的切面类型

Advisor:代表一般切面。Advice本身就是一个切面,对所有目标类所有方法都进行增强。

target,porxyInterfaces,interceptorNames

PointCardAdivaor:代表具有切点的切面。可以指定拦截目标类的某些方法。

–不等待切入点的切面

–带有切入点的切面

Spring的传统AOP自动代理

–基于Bean名称的自动代理

–基于切面信息的自动代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值