zoukankan      html  css  js  c++  java
  • spring 基础

    核心思想

    1,IOC 和 AOP 是一种思想,而不是一种技术
    2,在 spring 之前就已经存在了,之不是这两种思想在 spring 得到了非常好的技术实现
    

    IOC 和 DI

    1,Inversion of Control,控制反转
    2,控制:创建(实例化、管理)对象的权力,反转:把控制权交出来(交给 spring 的 IOC 容器)
    3,传统方式如果 A 依赖 B,那么会在 A 里创建 B 对象,在 spring 里面使用 @Autowired 即可
    4,IOC 和 DI 描述的是同一个事情,只是角度不同
    
    • IOC 是站在对象的角度,即 控制反转。程序需要什么对象,就到容器去取
    • DI 是站在容器的角度,即 依赖注入。程序需要什么对象,容器就推送给他什么对象

    AOP

    1,Aspect oriented Programming ⾯向切⾯编程
    2,OOP(面向对象) 的延续。面向对象能解决很多的代码重复问题。但是有局限性。比如每个接口需要增加额外的操作(比如接口耗时、日志统计等)
    
    • 在不改变原有业务逻辑的情况下,横切逻辑代码,从根本上解耦,避免重复代码
    • 切:代码是竖着执行,执行的是业务逻辑,业务逻辑之外的增强逻辑代码,可以想象成一把刀把业务横着切开了
    • 面:横切往往影响很多方法,每个方法都如同一个点,点多了构成一个面

    IOC 应用

    其实就是创建 bean 对象的一些操作
    

    bean 生命周期

    <bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton" />
    
    • singleton:单例模式,容器创建时创建 bean,每次使用都是这个 bean
    • prototype:多例模式,每次使用都创建新的 bean

    基于 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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
            <!--配置service对象-->
            <bean id="userService" class="com.lagou.service.impl.UserServiceImpl" />
        </beans>
    

    方式一:使用无参构造函数(默认)创建对象

    使用反射调用无参构造,如果当前类没有无参构造函数会创建失败

    <!-- id 必须唯一;class 指定该 bean 的实现类,反射创建的对象 -->
    <bean id="userService" class="com.lagou.service.impl.UserServiceImpl">
        <!-- 指定默认值,将调用 setName 方法 -->
        <property name="name" value="Rose"></property>
    </bean>
    

    方式二:使用静态工厂方法创建对象

    <!-- 定义 chinese Bean 由 PersonFactory 工厂的 getPerson(这是个静态方法) 方法创建 -->
    <bean id="chinese" class="com.mao.staticFactory.PersonFactory" factory-method="getPerson">
        <!-- getPerson 方法传参 -->
        <constructor-arg value="chinese"/>
        <!-- setMsg 传参 -->
        <property name="msg" value="我是中国人"/>
    </bean> 
    
    <!-- 创建american Bean -->
    <bean id="american" class="com.mao.staticFactory.PersonFactory" factory-method="getPerson">
        <constructor-arg value="american"/>
        <property name="msg" value="我是美国人"></property>
    </bean>
    
    public class PersonFactory {
        public static Person getPerson(String arg){
        if(arg.equalsIgnoreCase("chinese")){
            return new Chinese();
        } else {
            return new American();
        }
      }
    }
    

    分析 chinese bean 的创建

    • 将调用 PersonFactory.getPerson 完成实例化
    • 根据 constructor-arg = chinese,方法传入了 chinese,所以会返回 new Chinese()
    • 根据 <property name="msg" value="我是中国人"/> 会调用 Chinese 的 setMsg("我是中国人")
    • 得到的 bean:chinese:{msg:"我是中国人"}

    方式三:使用普通方法创建对象

    方法不是静态的,不用 static 修饰

    <!-- 配置工厂Bean,class指定该工厂的实现类,该Bean负责产生其他Bean实例 -->
    <bean id="personFactory" class="com.mao.instanceFactory.PersonFactory"/>
    
    <!-- 由实例工厂Bean的getPerson()方法,创建Chinese Bean, -->
    <bean id="ch" factory-bean="personFactory" factory-method="getPerson">
      <!-- 为该方法传入参数为chinese -->
      <constructor-arg value="chinese"/>
    </bean>
    
    <!-- 由实例工厂Bean的getPerson()方法,创建American Bean, -->
    <bean id="usa" factory-bean="personFactory" factory-method="getPerson">
      <constructor-arg value="american" />
    </bean>
    
    public class PersonFactory {
        // 不是静态方法(其实是不是都没关系,因为不管是否是静态的,都能调用到这个方法)
        public Person getPerson(String arg){
        if(arg.equalsIgnoreCase("chinese")){
            return new Chinese();
        } else {
            return new American();
        }
      }
    }
    

    基于注解

    不再使用 xml 配置文件,使用注解完成 bean 的定义和作用域等属性配置
    
    注解 对应 xml 标签 注解的地方 含义
    @Configuration xml配置文件 表名当前类是⼀个配置类
    @Bean xml 的 bean 标签 方法 方法名是 id 属性,return 类型是 class 属性
    有个属性 initMethod,初始化后执行,效果和 @PostConstruct 一致
    对于初始化后执行的操作还有一种方式:实现 InitializingBean 接口,这种性能要高些,因为不是反射完成的
    @PostConstruct bean 标签的 init-method 属性 方法 配合 @Bean 使用,初始化 bean 后执行
    @Scope bean 标签的 scope 属性 方法 和 @Bean 配合使用,指明作用域,单例还是多例
    @Lazy bean 标签的 lazy-init=true 方法 和 @Bean 配合使用,是否懒加载
    使用时才实例化 bean,而不是服务启动就实例化所有 bean
    @Value bean 的 property 属性标签 属性 实例化该 bean 时,调用 set 方法赋值
    1,@Value("#{xxx.xxx}"是把别的 bean 的值进行赋值
    2,@Value("${xxx.xxx}") 是把配置文件的值进行赋值(读取配置文件)
    3,@Value("xxx") 直接赋值基本类型
    @ComponentScan context:component-scan 扫描包范围,该路径下的 bean 交给 spring 管理
    1,一般使用 @ComponentScans,全局出现一次
    @ComponentScans(value = {@ComponentScan(value = "io.mieux.controller"),@ComponentScan(value = "io.mieux.service")})
    2,value 和 basePackages 功能相同
    3,basePackageClasses 属性把指定的类添加到容器中
    4,includeFilters 添加某些类到容器中,即使这些类没有标注 @Component 注解
    5,指定某些类不添加到容器中
    @PropertySource context:property-placeholder location="classpath:xxx.properties" 引⼊外部属性配置⽂件,利用其数据构建 bean,一般配合@Configuration、 @ConfigurationProperties、@EnableConfigurationProperties 等注解完成
    @Import - 类或注解 也是把指定的类添加到容器中,有三种用法,后面详细讲解
    @Component - 类或接口 依赖注入 bean,还有 @Service、@Controller、@Repository,必须在 @ComponentScan 指定的路径下

    循环依赖

    两个或以上的对象互引用对方,造成创建 bean 时死循环
    
    public class A{
        private B b;
    }
    public class B{
        private A a;
    }
    
    • 产生原因
      • spring 在实例化 A 的时候,发现其属性引用了 B
      • 实例化 B,但是在 B 内部也引用了 A(此时 A 还没有创建好,ApplicationContext.getBean(A)获取不到,于是就会创建 A)
      • ...
    • spring 解决方案
      • 实例化 A 的时候,创建好了,但还没有完成初始化(成员变量赋值),这时把 A 先暴露出去(三级缓存)
      • 为 A 初始化,发现成员变量依赖 B,B 还没有创建,于是实例化 B,B 实例化完成
      • 为 B 初始化,发现成员变量依赖 A,这时候已经能获取到 A 了,B 初始化完成,这时能拿到 B 了,再完成 A 的初始化

    AOP 应用

    本质是在不改变原有业务逻辑的情况下增强横切逻辑,横切逻辑代码往往是权限校验代码、⽇志代码、事务控制代码、性能监控代码
    说人话就是 一些方法要添加相同的操作功能,不到每个方法里添加相同的代码块,单独写一个方法,在每个方法执行时能执行到新添加的这个方法
    

    术语

    • 连接点(Joinpoint):目标方法执行的某个时机,执行前,执行后,抛出异常时等
    • 切点(Pointcut):具体方法(定义类也会落实到类下面的所有方法)
    • 通知(advice):前置、后置、环绕、异常、返回通知,具体增强的逻辑是啥
    • 目标对象(target):被代理的对象
    • 代理对象(proxy):代理对象(动态代理,有接口就 JDK ,没有接口就 CGLIB)
    • 织入(Weaving):编译期、类装载、动态代理织入三种方式,spring 采用动态代理方式,AspectJ 采用编译期和类装载方式
    • 切面(Aspect):是一个类,定义切点、连接点、通知等

    基于 xml

    基于注解

    见以前我写的 demo(https://gitee.com/huanggyaaa/springboot/tree/master/aspect),可以切注解、类、方法、接口,有前置、后置、环绕、返回等通知  
    这是基于 springboot 的,springboot 的自动加载功能(@EnableAutoConfiguration)会自动加载事务相关的信息,所以可以不用 @EnableTransactionManagement 注解
    

    声明式事务底层

    用两个注解即可完成,@EnableTransactionManagement 和 @Transactional,分析下这俩货的底层做了啥操作
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    // 这里导入了 TransactionManagementConfigurationSelector 类
    @Import({TransactionManagementConfigurationSelector.class})
    public @interface EnableTransactionManagement {
        boolean proxyTargetClass() default false;
    
        AdviceMode mode() default AdviceMode.PROXY;
    
        int order() default 2147483647;
    }
    
    // @Import 注解用法之一就是 类 必须实现 ImportSelector 接口并重写 selectImports 方法
    public class TransactionManagementConfigurationSelector extends 
        // 省略...
        // 像容器又添加了两个组件:AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration
        protected String[] selectImports(AdviceMode adviceMode) {
            switch(adviceMode) {
            case PROXY:
                return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[]{this.determineTransactionAspectClass()};
            default:
                return null;
            }
        }
        // 省略...
    }
    

    AutoProxyRegistrar组件

    public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        // 省略 ...
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
           // 省略 ...
                        if (mode == AdviceMode.PROXY) {
                            // 这里又注册了一个组件
                            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                        }
            }
            // 省略 ...
        }
    }
    
    public abstract class AopConfigUtils {
        // 省略 ...
        @Nullable
        public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
            return registerAutoProxyCreatorIfNecessary(registry, (Object)null);
        }
        // 省略 ...
        @Nullable
        public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
            return registerOrEscalateApcAsRequired(
                // 最终注册了 InfrastructureAdvisorAutoProxyCreator 的 bean
                // 这个类继承了 AbstractAutoProxyCreator
                InfrastructureAdvisorAutoProxyCreator.class, registry, source);
        }
        // 省略 ...
    }
    

    ProxyTransactionManagementConfiguration 组件

    @Configuration(proxyBeanMethods = false)
    @Role(2)
    public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
        public ProxyTransactionManagementConfiguration() {
        }
    
        @Bean(name = {"org.springframework.transaction.config.internalTransactionAdvisor"})
        @Role(2)
        public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
            // 事务增强器
            BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
            // 向事务增强器中注⼊ 属性解析器 transactionAttributeSource
            advisor.setTransactionAttributeSource(transactionAttributeSource);
            // 向事务增强器中注⼊ 事务拦截器 transactionInterceptor
            advisor.setAdvice(transactionInterceptor);
            if (this.enableTx != null) {
                advisor.setOrder((Integer)this.enableTx.getNumber("order"));
            }
    
            return advisor;
        }
    
        @Bean
        @Role(2)
        // 属性解析器 transactionAttributeSource,作用之一就是 解析@Transaction注解
        public TransactionAttributeSource transactionAttributeSource() {
            return new AnnotationTransactionAttributeSource();
        }
    
        @Bean
        @Role(2)
        // 事务拦截器 transactionInterceptor
        public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
            // interceptor.invoke 调用 interceptor.invokeWithinTransaction,完成原有的逻辑和增强的通知执行
            TransactionInterceptor interceptor = new TransactionInterceptor();
            interceptor.setTransactionAttributeSource(transactionAttributeSource);
            if (this.txManager != null) {
                interceptor.setTransactionManager(this.txManager);
            }
    
            return interceptor;
        }
    }
    
    • 可以看到 @EnableTransactionManagement 导入了两个类:AutoProxyRegistrarProxyTransactionManagementConfiguration
    • AutoProxyRegistrar 组件引入了 InfrastructureAdvisorAutoProxyCreator 类,这个类继承了 AbstractAutoProxyCreator 是一个后置处理器
    • ProxyTransactionManagementConfiguration 组件完成 AOP 通知操作
  • 相关阅读:
    每天学习算法二
    每天学习算法 一
    数据量基础
    SQL server数据库创建代码,filegroup文件组修改,
    SQL学习笔记之 数据库基础(一)
    Oracle的查询-条件表达式
    Oracle的查询-单行查询
    Oracle 的查询-scott用户介绍
    Oracle的基本操作-序列的使用
    Oracle的基本操作-修改表结构、数据的增删改查
  • 原文地址:https://www.cnblogs.com/huanggy/p/15151416.html
Copyright © 2011-2022 走看看