精华内容
下载资源
问答
  • Spring IOCAOP的认识及项目中应用场景
    千次阅读
    2021-10-16 10:05:31

    目录

    IOC模块

    BeanFactory、applicationContext的容器区别

    Bean加载流程、各个接口的应用场景

    Spring如何处理循环依赖

    spring事件机制?

    AOP模块

    对spring aop的认识?aop实际应用场景

    spring如何支持可扩展的?

    spring事物的实现原理


    IOC模块

    BeanFactory、applicationContext的容器区别

    先从BeanFactory和applicationContext的源码,来大致看下这两个类

    BeanFactory定义的是一个接口,具体的实现交给子类完成(DefaultListableBeanFactory成熟bean工厂等),定义了些对bean最基本的操作, 主要是获取bean、判断IOC容器中是否存在该bean、判断bean是单例还是多例模式、bean的class类型匹配等,所以通常认为beanFactory是IOC的低级容器。

    public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
    		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    
    }

    applicationContext接口在定义时,继承了EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver接口,接下来逐一分析

    一、ListableBeanFactory、HierarchicalBeanFactory:作为Beanfactory的子类扩展了一些接口,通过继承该接口,可以知道application的具体实现是具备对bean的基本操作的。

    二、EnvironmentCapable:表示当前应用程序运行环境的接口。 为应用程序环境的两个关键方面建模:配置文件和属性

    三、MessageSource:用于解析消息的策略接口,支持此类消息的参数化和国际化。

    四、ApplicationEventPublisher:定义了事件发布的接口

    五、ResourcePatternResolver:支持多资源加载。

    六、bean的一系统aware实现在加载bean时执行并放入IOC容器中,IOC管理着bean的生命周期

    由此可见applicationContext作为高级容器,确实比beanFactory提供的功能强大很多,所以通常在程序是使用applicationContext。

    Bean加载流程、各个接口的应用场景

    Bean的加载流程:

    根据上图,在源码中一一校验,首先看下IOC容器启动时:

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    			throws BeansException {
    
            // 创建ClassPathXmlApplicationContext 加载进行加载bean时,会走调用该方法,可以看到后续refresh(),该方法是创建IOC容器的关键
    		super(parent);
    		setConfigLocations(configLocations);
    		if (refresh) {
    			refresh();
    		}
    	}

    public void refresh() throws BeansException, IllegalStateException {
            // 对startupShutdownMonitor加锁,startupShutdownMonitor是有着
            // 刷新、创建的同步监视器作用的Object对象,本身并无其他作用
    		synchronized (this.startupShutdownMonitor) {
    			// 为refresh做准备工作,如:容器重置为活跃状态,通过ConfigurableEnvironment
                // 替换Servlet相关的属性源,验证setRequiredProperties指定的每个属性
                // 是否存在并解析为非null值、重置applicationEvent的集合等。
    			prepareRefresh();
    
    			// 刷新bean工厂,首先会通过refreshBeanFactory(),关闭之前的bean工厂,
                // 并初始化一个新的bean工厂(关闭bean工厂的同时,会先销毁之前的beans,
                // 通过查询源码可以看到在DefaultSingletonBeanRegistry的destroyBean()中
                // 调用bean.destroy(),由此也可以看出,当容器进行销毁bean时,若bean实现了        
                // DisposableBean接口destroy()方法,会在销毁前执行bean具体实现)
    			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    			// 配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器
    			prepareBeanFactory(beanFactory);
    
    			try {
    				// 允许在上下文子类中对bean工厂进行后处理(主要是添加
                    // ServletContextAwareProcessor的后置处理器,并为beanFactory注册从
                    // ConfigurableEnvironment中得到的某些bean,比如:servletContext、
                    // servletConfig、contextParameters、contextAttributes)
    				postProcessBeanFactory(beanFactory);
    
    				// 调用BeanFactory的PostProcessors,这些处理器是在bean定义中向容器注册的(
                    // 第一步:加载实现了PriorityOrdered接口的PostProcessors
                    // 第二步:加载实现了Ordered接口的PostProcessors
                    // 通用的PostProcessors通常都是有顺序的所以根据这两个接口设置的order来决定执行顺序
                    // 第三步:调用实现Ordered的BeanDefinitionRegistryPostProcessors(bean自行实现的)
                    // 第四步:调用所有其他的BeanDefinitionRegistryPostProcessors,直到没有其他的出现
                    // 最后:调用到目前为止所处理的所有处理器的postProcessBeanFactory回调)
    				invokeBeanFactoryPostProcessors(beanFactory);
    
    				// 注册bean的processors,在bean创建的过程中被调用(步骤和上个方法相似,最后会将processors注册到IOC容器中)
    				registerBeanPostProcessors(beanFactory);
    
    				// 对消息源进行初始化
    				initMessageSource();
    
    				// 初始化context的事件机制
    				initApplicationEventMulticaster();
    
    				// 初始化其他的特殊bean
    				onRefresh();
    
    				// 检查监听bean,并注册到IOC容器(将监听bean设置initApplicationEventMulticaster()初始化的事件机制中)
    				registerListeners();
    
    				// 实例化所有的(non-lazy-init)单件(非懒加载的单例bean)
                    // DefaultListableBeanFactory的preInstantiateSingletons()中,
                    //if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit())可见启动时,会先加载 非懒加载单例bean。
    				finishBeanFactoryInitialization(beanFactory);
    
    				// 初始化 LifecycleProcessor、刷新LifecycleProcessor、发送发布通知等。
    				finishRefresh();
    			}
    
    			catch (BeansException ex) {
    				if (logger.isWarnEnabled()) {
    					logger.warn("Exception encountered during context initialization - " +
    							"cancelling refresh attempt: " + ex);
    				}
    
    				// 销毁之前的beans,通过查询源码可以看到在DefaultSingletonBeanRegistry的destroyBean()中
                // 调用bean.destroy(),容器销毁时,销毁bean时,回调bean实现的destroy()方法
    				destroyBeans();
    
    				// 容器活跃状态改为false
    				cancelRefresh(ex);
    
    				// Propagate exception to caller.
    				throw ex;
    			}
    
    			finally {
    				// 清空spring中常见缓存(如:反射中缓存的方法和属性、classLoader类加载器等)
    				resetCommonCaches();
    			}
    		}
    	}

    通过上述源码,可以看到容器关闭时,会调用 bean.destroy(),对bean的销毁最终会调用DisposableBeanAdapter的destory()方法,会判断是否是DisposableBean的实例,然后调用bean重写的destroy()方法,最终通过反射,调用destroyMethod()完成对对象的销毁。

    接下来看创建bean的流程,创建bean,是当第一次用到bean时,向IOC容器去getBean(),由于源码太长,故画出流程图,可根据流程图查询源码:

    通过对源码的查看,可以验证出之前的加载bean的流程是正确的。

    应用场景:aware接口,:像 ApplicationContextAware可以将IOC容器赋值到某个类的属性中。BeanPostProcessor的实现类,可以对某一类bean完成一定的增强效果(例:记录方法的执行时间,若超过指定秒数,输出告警日志)、或初始化资源、又或者进行项目初始化的数据缓存。

    具体示例:

    定义AsyncSpecifiedBeanPostProcessor接口,后置处理器进行中间件预热

    @Bean
    public AsyncSpecifiedBeanPostProcessor redisPostProcessorConfigurer(){
    			return new AsyncSpecifiedBeanPostProcessor<RedisTemplate>() {
    
    				@Override
    				public Class<RedisTemplate> getBeanType() {
    					return RedisTemplate.class;
    				}
    
    				@Override
    				public void postProcessAfterInitialization(RedisTemplate redisTemplate, String beanName) {
    					//调用redis初始化,由于第一次redis调用会比较慢(尤其是其中Cat监控会给redisTemplate加上proxy,由于第一次生成proxy类比较慢,大约需要500ms,刚启动时如果有大量redis调用,都需要500多ms),所以需要调用预热一次,加速启动完成后的访问速度
    					try {
    						redisTemplate.execute(new RedisCallback() {
    							@Override
    							public Object doInRedis(RedisConnection connection) throws DataAccessException {
    								Jedis jedis = (Jedis) connection.getNativeConnection();
    								return jedis.get("justForInitTest");
    							}
    						});
    					}catch(Exception e){
    						if(redisTemplate.getConnectionFactory() instanceof JedisConnectionFactory) {
    							JedisConnectionFactory cf = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
    							logger.error("Init redisTemplate(beanName:{}) failed, currentHost:{}, port:{}", beanName, cf.getHostName(), cf.getPort(), e);
    						}else{
    							throw e;
    						}
    					}
    				}
    			};
    		}
    @Component
    public class CacheBeanPostProcessor implements BeanPostProcessor, Ordered {
    
        @Override
        public int getOrder() {
            return 0;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof CacheInterface) {
                // 实现该接口的具体实例来完成加载缓存
                ((CacheInterface) bean).loadCache();
            }
            return bean;
        }
    }

    Spring如何处理循环依赖

    【源码解析】Spring如何处理循环依赖?_旺仔的博客-CSDN博客

    spring事件机制?

    AOP模块

    对spring aop的认识?aop实际应用场景

    aop是通过动态代理来实现的,spring管理的bean是通过jdk动态代理、或者cglib动态代理生成的代理对象,而定义好切面类,就可以在代理对象调用目标方法的前后来增加方法。

    在《Spring核心原理》中,从ProxyFactoryBean的getObject(),来分析整个aop的原理,可以参考,不过在实际的启动运行流程中,是通过获取bean时调用的initializeBean()方法,可见下图

     createAopProxy()会根据 targetClass是接口、动态代理类,通过JDK生成代理类,否则使用JDK生成。两种动态代理的方式分别在JdkDynamicAopProxy的invoke方法、CglibAopProxy的intercept方法,两种方式都是会将解析出来的advice根据目标类、方法来matches出目标方法的所有advice(List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)

    )并根据适配器模式匹配出具体是哪个类型的advice,然后构造出ReflectiveMethodInvocation()对象去执行proceed(),这个方法会循环advice,进行动态匹配判断,执行目标advice,根据advice是前置、后置、异常,来执行代码顺序。如下:
     

    public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
    
    	private MethodBeforeAdvice advice;
    
    
    	/**
    	 * Create a new MethodBeforeAdviceInterceptor for the given advice.
    	 * @param advice the MethodBeforeAdvice to wrap
    	 */
    	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
    		Assert.notNull(advice, "Advice must not be null");
    		this.advice = advice;
    	}
    
        // 执行前置方法后,再执行方法调用
    	@Override
    	public Object invoke(MethodInvocation mi) throws Throwable {
    		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    		return mi.proceed();
    	}
    
    }
    后置、异常通知类似,可参看AfterReturningAdviceAdapter、ThrowsAdviceAdapter源码。关于bean的切面是如何添加到advised中,经过查阅资料和debug源码,发现在创建bean的前置postproccess中,在遍历调用前置处理器时,SmartInstantiationAwareBeanPostProcessor的AbstractAutoProxyCreator实现了对创建的切面类记录。
    

    aop的应用场景:像spring通过@Transaction自动开启关闭事务、通过@Async来异步执行方法,都是对aop的应用,

    一、因此自定义注解是一种场景,在项目中可以通过自定义注解,然后增加自定义注解的切面类,就可以对使用该注解的方法进行增强

    二、通过定义切面类,将某个包下的某些命名的类或类的方法进行增强

    spring如何支持可扩展的?

    spring事物的实现原理

    更多相关内容
  • IoC DI 的区别? 什么是 AOPAOP 解决了什么问题? AOP 为什么叫做切面编程? 首先声明:IoC & AOP 不是 Spring 提出来的,它们在 Spring 之前其实已经存在了,只不过当时更加偏向于理论。Spring 在...

    这篇文章会从下面从以下几个问题展开对 IoC & AOP 的解释

    • 什么是 IoC?
    • IoC 解决了什么问题?
    • IoC 和 DI 的区别?
    • 什么是 AOP?
    • AOP 解决了什么问题?
    • AOP 为什么叫做切面编程?

    首先声明:IoC & AOP 不是 Spring 提出来的,它们在 Spring 之前其实已经存在了,只不过当时更加偏向于理论。Spring 在技术层次将这两个思想进行了很好的实现。

    什么是 IoC

    IoC (Inversion of control )控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题。 

    例如:现有类 A 依赖于类 B

    • 传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来
    • 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象,而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面过去即可。

    从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情)

    为什么叫控制反转

    控制 :指的是对象创建(实例化、管理)的权力

    反转 :控制权交给外部环境(Spring 框架、IoC 容器)

      

    IoC 解决了什么问题

    IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢? 

    1. 对象之间的耦合度或者说依赖程度降低;
    2. 资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。

    例如:现有一个针对 User 的操作,利用 Service 和 Dao 两层结构进行开发

    在没有使用 IoC 思想的情况下,Service 层想要使用 Dao 层的具体实现的话,需要通过 new 关键字在UserServiceImpl 中手动 new 出 IUserDao 的具体实现类 UserDaoImpl(不能直接 new 接口类)。

    很完美,这种方式也是可以实现的,但是我们想象一下如下场景:

    开发过程中突然接到一个新的需求,针对对IUserDao 接口开发出另一个具体实现类。因为 Server 层依赖了IUserDao的具体实现,所以我们需要修改UserServiceImpl中 new 的对象。如果只有一个类引用了IUserDao的具体实现,可能觉得还好,修改起来也不是很费力气,但是如果有许许多多的地方都引用了IUserDao的具体实现的话,一旦需要更换IUserDao 的实现方式,那修改起来将会非常的头疼。

    img

    使用 IoC 的思想,我们将对象的控制权(创建、管理)交有 IoC 容器去管理,我们在使用的时候直接向 IoC 容器 “要” 就可以了

    img

    IoC 和 DI 的区别

    IoC(Inverse of Control:控制反转)是一种设计思想 或者说是某种模式。这个设计思想就是 将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。 

    IoC 最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。

    什么是 AOP

    AOP:Aspect oriented programming 面向切面编程,AOP 是 OOP(面向对象编程)的一种延续。 

    下面我们先看一个 OOP 的例子。

    例如:现有三个类,Horse、Pig、Dog,这三个类中都有 eat 和 run 两个方法。

    通过 OOP 思想中的继承,我们可以提取出一个 Animal 的父类,然后将 eat 和 run 方法放入父类中,Horse、Pig、Dog通过继承Animal类即可自动获得 eat() 和 run() 方法。这样将会少些很多重复的代码。

    img 

    OOP 编程思想可以解决大部分的代码重复问题。但是有一些问题是处理不了的。比如在父类 Animal 中的多个方法的相同位置出现了重复的代码,OOP 就解决不了。

    /**
     * 动物父类
     */
    public class Animal {
    
        /** 身高 */
        private String height;
    
        /** 体重 */
        private double weight;
    
        public void eat() {
            // 性能监控代码
            long start = System.currentTimeMillis();
    
            // 业务逻辑代码
            System.out.println("I can eat...");
    
            // 性能监控代码
            System.out.println("执行时长:" + (System.currentTimeMillis() - start)/1000f + "s");
        }
    
        public void run() {
            // 性能监控代码
            long start = System.currentTimeMillis();
    
            // 业务逻辑代码
            System.out.println("I can run...");
    
            // 性能监控代码
            System.out.println("执行时长:" + (System.currentTimeMillis() - start)/1000f + "s");
        }
    }
    


    这部分重复的代码,一般统称为 横切逻辑代码

    img 

    横切逻辑代码存在的问题:

    1. 代码重复问题
    2. 横切逻辑代码和业务代码混杂在一起,代码臃肿,不变维护


    AOP 就是用来解决这些问题的

    AOP 另辟蹊径,提出横向抽取机制,将横切逻辑代码和业务逻辑代码分离

    img 

    代码拆分比较容易,难的是如何在不改变原有业务逻辑的情况下,悄无声息的将横向逻辑代码应用到原有的业务逻辑中,达到和原来一样的效果。

    AOP 解决了什么问题

    通过上面的分析可以发现,AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。 

    AOP 为什么叫面向切面编程

    :指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑

    :横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念

    参考文章:https://blog.csdn.net/qq_34337272/article/details/106405900?spm=1001.2014.3001.5501 

    展开全文
  • 深入理解Spring IOC和AOP

    2021-02-16 16:16:54
    1. 什么是 Spring 框架? 1.1Spring简介 Spring 是一种轻量级开发...这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息测试模块。比如:Core Container 中的 Core 组件是Spring 所有组件

    1. 什么是 Spring 框架?

    1.1Spring简介

    Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。Spring 官网:https://spring.io/。

    我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。比如:Core Container 中的 Core 组件是Spring 所有组件的核心,Beans 组件和 Context 组件是实现IoC和依赖注入的基础,AOP组件用来实现面向切面编程。

    简单来说,Spring是一个轻量级的==控制反转(IoC)面向切面(AOP)==的容器框架。

    Spring 官网列出的 Spring 的 6 个特征:

    • 核心技术 :依赖注入(DI),AOP,事件(events),资源,i18n,验证,数据绑定,类型转换,SpEL。
    • 测试 :模拟对象,TestContext框架,Spring MVC 测试,WebTestClient。
    • 数据访问 :事务,DAO支持,JDBC,ORM,编组XML。
    • Web支持 : Spring MVC和Spring WebFlux Web框架。
    • 集成 :远程处理,JMS,JCA,JMX,电子邮件,任务,调度,缓存。
    • 语言 :Kotlin,Groovy,动态语言。

    1.2Spring的好处

    ①方便解耦,简化开发:

    • Spring就是一个大工厂,专门负责生成Bean,可以将所有对象创建和依赖关系维护由Spring管理。

    ②AOP编程的支持

    • Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

    ③声明式事务的支持:

    • 只需要通过配置就可以完成对事务的管理,而无需手动编程

    ④方便程序的测试:

    • Spring对Junit4支持,可以通过注解方便的测试Spring程序

    ⑤方便集成各种优秀框架:

    • Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的支持

    ⑥降低JavaEE API的使用难度 Spring:

    • 对JavaEE开发中一些难用的API(JDBC、JavaMail、远程调webservice用等),都提供了封装,使这些API应用难度大大降低

    1.3Spring体系结构

    image-20210216161534107

    2.理解Spring IoC

    2.1IoC简介

    IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spring框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。

    如何理解好IoC呢?理解好IoC的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

    • 谁控制谁,控制什么: 传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由IoC容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

    • 为何是反转,哪些方面反转了: 有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

    图例说明:

    传统程序设计都是主动去创建相关对象然后再组合起来:

    image-20210216152102765

    当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了,如图所示:

    image-20210216152132082

    其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。

    IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。


    2.2IoC的好处

    将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

    Spring 时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置不太好,于是 SpringBoot 注解配置就慢慢开始流行起来。

    IoC的思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度

    也就是说,甲方要达成某种目的不需要直接依赖乙方,它只需要达到的目的告诉第三方机构就可以了,比如甲方需要一双袜子,而乙方它卖一双袜子,它要把袜子卖出去,并不需要自己去直接找到一个卖家来完成袜子的卖出。它也只需要找第三方,告诉别人我要卖一双袜子。这下好了,甲乙双方进行交易活动,都不需要自己直接去找卖家,相当于程序内部开放接口,卖家由第三方作为参数传入。甲乙互相不依赖,而且只有在进行交易活动的时候,甲才和乙产生联系。反之亦然。这样做什么好处么呢,甲乙可以在对方不真实存在的情况下独立存在,而且保证不交易时候无联系,想交易的时候可以很容易的产生联系。甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。因为交易由第三方来负责联系,而且甲乙都认为第三方可靠。那么交易就能很可靠很灵活的产生和进行了。

    这就是IoC的核心思想。生活中这种例子比比皆是,支付宝在整个淘宝体系里就是庞大的IoC容器,交易双方之外的第三方,提供可靠性可依赖可灵活变更交易方的资源管理中心。另外人事代理也是,雇佣机构和个人之外的第三方。


    2.3依赖注入和控制反转

    在以上的描述中,诞生了两个专业词汇,依赖注入控制反转

    IoC(Inversion of Control):控制反转。
    DI(Dependency Injection):依赖注入。

    控制反转是目的,依赖注入是实现控制反转的手段。

    所谓的依赖注入,则是,甲方开放接口,在它需要的时候,能够讲乙方传递进来(注入)
    所谓的控制反转,甲乙双方不相互依赖,交易活动的进行不依赖于甲乙任何一方,整个活动的进行由第三方负责管理。

    控制反转是一种面向对象的思想,它是一种宽泛的概念,只要一个类将对它内部状态的控制权交由其他机制去完成即为『控制反转』。控制反转是为了降低类与类之间的耦合度。而Spring采用依赖注入这一具体的手段来达到控制反转的目的。

    依赖注入详解

    DI—Dependency Injection,即“依赖注入”组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。**依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。**通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

    理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:

    谁依赖于谁:当然是应用程序依赖于IoC容器

    为什么需要依赖: 应用程序需要IoC容器来提供对象需要的外部资源

    谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象

    ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

    IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”

    一个类内部往往有很多成员变量,如:

    class A {
        private Person chaimm;
    }
    

    上述代码在面向对象中可以描述为:

    • A类和Person类之间存在依赖关系;
    • A依赖于Person;
    • A为依赖类;
    • Perosn为被依赖类;

    通常情况下,依赖类需要自己去创建并维护被依赖类的对象,如:

    class A {
        private Person chaimm = new Person();
    }
    

    但依赖注入的做法是:将被依赖对象的创建与维护工作交由专门的机构,而依赖类中只需要声明所需要的成员变量。
    也就是说,依赖类原本需要主动去获取对象,但采用依赖注入后对象由第三方机构提供,自己仅需声明需要什么对象即可。
    这样做的目的就是为了降低两个类之间的耦合程度。
    PS:在Spring中,那个创建、管理对象的机构就称为『IoC Service Provider』。

    但此时还没体现出依赖注入能降低耦合度这一点,只有当依赖注入与面向接口编程结合起来,才能真正发挥依赖注入的优势。接下来先介绍一下『面向接口编程』。

    什么是面向接口编程?
    一个类依赖其他类的目的是为了获取其他类所提供的服务,可能这种服务有多种实现,我们可能需要根据不同的场景使用不同的实现。此时,我们可以使用多态,将同一功能的多种实现抽象出一个接口,并为所有实现定义一套相同的API。在使用时声明接口类型的变量而非实现类的变量,并将实现类的对象赋给接口变量,最后用接口变量去调用实现类的服务,如:

    class A {
        private Super super = new SuperImpl1();
    
        public static void main ( String[] args ) {
            // 使用Super提供的服务
            super.method1();
            super.method2();
            super.method3();
        }
    }
    

    这样,当想使用SuperImpl2提供的功能时,只需替换Super的实现类,其他地方不做任何变化:

    private Super super = new SuperImpl2();
    

    上述过程就是面向接口编程的思想:若某一类服务有多种不同的实现,我们需要抽象出一个接口,并在接口中定义一套API。在使用时声明接口类型变量,并用实现类的对象赋值。接下来通过接口类型的变量调用服务即可。当功能发生变化时,仅需替换实现类即可。

    在面向接口编程的基础上使用依赖注入的好处
    上述过程如果要换一种实现,就必须要修改A类的代码,再重新编译。而使用了依赖注入后,由于依赖类不需要自己创建维护被依赖对象,该过程由IoC Service Provider完成。因此,当需要替换实现类时,只需在IoC Service Provider中修改,被依赖类、依赖类都不会受到影响,此时这两个类是松耦合的。

    依赖注入的三种方式

    参考博客:推荐基于Lombok的Spring注入方式(基于构造器注入)及快速获取Spring容器中管理的对象


    2.4Spring IoC的初始化过程

    image-20210216143415707


    2.5Spring IoC源码阅读

    参考文章:https://javadoop.com/post/spring-IoC


    2.6Spring IOC的使用

    可参考:


    3.理解Spring AOP

    3.1AOP简介

    AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性

    AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。

    image-20210216155215354


    3.2为什么需要 AOP

    想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。


    3.3AOP 实现分类

    AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的多个方法的源代码,看到这其实应该明白了,AOP 其实就是代理模式的典型应用。
    按照 AOP 框架修改源代码的时机,可以将其分为两类:

    • 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
    • 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。

    下面给出常用 AOP 实现比较:
    image-20210216155841260

    关于动态代理可参考我的另一篇博客:实例理解JDK动态代理和Cglib动态代理及其区别


    3.4AOP 术语

    AOP 领域中的特性术语:

    • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
    • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
    • 切点(PointCut): 可以插入增强处理的连接点。
    • 切面(Aspect): 切面是通知和切点的结合。
    • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
    • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。

    3.5Spring AOP

    Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib ,这时候Spring AOP会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

    image-20210216152837816

    当然也可以使用 AspectJ ,Spring AOP 已经集成了AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。

    使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。

    Spring AOP的使用,可参考:Spring AOP——Spring 中面向切面编程


    AOP,Spring AOP 和 AspectJ AOP

    AOP

    AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理。

    AOP 的实现并不是因为 Java 提供了什么神奇的钩子,可以把方法的几个生命周期告诉我们,而是我们要实现一个代理,实际运行的实例其实是生成的代理类的实例。


    对比Spring AOP 和 AspectJ AOP

    Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

    Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,

    如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。


    Spring AOP:

    • 它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,如果没有接口,使用 CGLIB 实现。大家一定要明白背后的意思,包括什么时候会不用 JDK 提供的动态代理,而用 CGLIB 实现。
    • Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,这也是为什么我们不需要显式引入这两个依赖
    • Spring 的 IOC 容器和 AOP 都很重要,Spring AOP 需要依赖于 IOC 容器来管理。
    • 如果你是 web 开发者,有些时候,你可能需要的是一个 Filter 或一个 Interceptor,而不一定是 AOP。
    • Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法。
    • Spring 提供了 AspectJ 的支持,一般来说我们用纯的 Spring AOP 就够了。
    • 很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。

    AspectJ:

    • AspectJ 出身也是名门,来自于 Eclipse 基金会,link:https://www.eclipse.org/aspectj

    • 属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:

      • Compile-time weaving:编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
      • Post-compile weaving:也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
      • Load-time weaving:指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar
    • AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。

    • 因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。

    关于AspectJ的使用,可参考:AspectJ 使用介绍


    参考:

    展开全文
  • Spring IOC和AOP

    2021-09-22 11:20:49
    2 .IOC控制反转3.IOC的两种实现4.Bean的管理5:DI和IOC6.scope7.spring的单例安全8.spring bean的常见生命周期9.Spring 怎么解决循环依赖问题?情景一(没有循环依赖)----一级缓存情景二(有循环依赖,没有Aop) --...


    IOC部分:

    1.Spring是什么?

    Spring是一个生态,可以构建java应用所需要的一切基础设施。通常spring指的是spring frameWork.
    一般的生态来说:

    • 1.Spring FrameWork

    • 2.SpringBoot
      增加了自动配置
      总结一下,其实就是 Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可

    • 3.SpringMVC

    • 4.SpringCloud
      分布式的springboot,适用于分布式

    而spring 是一个轻量级开源框架:
    IOC:控制翻转
    AOP:面向切面编程


    2 .IOC控制反转

    本意: 对象的创建由我们自己new转到了spring ioc容器中,由spring ioc容器统一管理、
    这样的好处: 降低对象间的耦合度
    底层分析: xml配置文件、反射、简单工厂模式
    我们通过读取xml配置文件(bean id+class),通过读取类的全路径,来进行反射创建对象,然后这个过程是由spring ioc完成的,我们只需要调用它提供的方法即可获得对象,这是简单工厂模式。


    3.IOC的两种实现

    1)BeanFactory接口
    这个接口是基本实现,一般不提供开发人员使用,并且加载配置文件的时候是懒加载,不会创建对象。
    2)ApplicationContext接口(其中实现的是BeanFactory接口)
    这个接口是提供给开发人员使用的,有相对多的功能,加载配置文件的就会创建对象,所以相对式慢启动、快响应。


    4.Bean的管理

    1)创建对象
    2)为对象设置属性
    一般分为基于xml的配置文件和基于注解方式的实现:
    xml文件:
    创建对象:在xml文件配置bean
    注入属性(DI):构造注入/设置注入(set),可以注入简单属性的值,也可以注入其他类的对象,包括注入外部bean、注入内部bean、

    基于注解:
    创建对象:在xml文件配置component-scan,然后再要创建对象的类上加入注解:@component、@service、@Reposity、@Controller
    注入属性(DI):在属性上加入注解:@Autowire、@Vlaue、@Qualifier、@Resource


    5:DI和IOC

    可以看到IOC式控制翻转,主要是创建对象的思想,而真正的实现是由反射+简单工厂,然后通过DI技术实现对象的属性赋值


    6.scope

    一般是单例、可以设置多例、还有不常用session、request,一次请求创建一个bean,一个会话创建一个bean


    7.spring的单例安全

    单例:一般如果涉及到无状态的bean(没有属性),那么肯定用单例,并且安全
    但是如果有状态的bean,单例则不安全了,我们一般用多例模式;当然还可以在单例模式下设置属性ThreadLocal来保证每个线程有自己的属性。


    8.spring bean的常见生命周期

    简单来说:
    创建对象---->注入属性---->后置处理器的Before方法------>初始化方法-------->后置处理器的After方法------>获得对象
    销毁对象------>调用destory方法(写了才有用)
    在这里插入图片描述
    为了更好理解,可以重构成实例化、属性注入、初始化、销毁四个主要部分,其余部分相当于使用AOP技术,如果实现了相关接口,才会有这些过程。

    • 1.BeanFactoryPostProcessor的bean定义
    • BeanFactoryPostProcessor接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
      说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性
    • 2.InstantiationAwareBeanPostProcessor的bean定义
    • postProcessBeforeInstantiation方法
    • 3.实例化
    • 4.InstantiationAwareBeanPostProcessor的bean定义
    • postProcessAfterInstantiation方法
    • 5.注入属性
    • 6.Aware接口
      【BeanNameAware接口】调用BeanNameAware.setBeanName()
      【BeanFactoryAware】调用BeanFactoryAware.setBeanFactory()
      【ApplicationContextAware】调用ApplicationContextAware.setApplicationContext()
    • 7.BeanPostProcessor的bean定义
    • postProcessBeforeInitialization方法
    • 8.InitializingBean的接口
    • InitializingBean.afterPropertiesSet()方法
    • 9.初始化init
    • 10.BeanPostProcessor的bean定义
    • postProcessAfterInitialization方法
    • 11.DisposableBean接口
    • destroy()方法
    • 12.自定义init_destory()方法

    9.Spring 怎么解决循环依赖问题?

    • 三级缓存
    • singletonObjects 一级缓存
    • earlySingletonObjects 二级缓存
    • singletonFactories 三级缓存

    情景一(没有循环依赖)----一级缓存

    在这里插入图片描述

    情景二(有循环依赖,没有Aop) -----二级缓存

    在这里插入图片描述
    最后把半成品池(二级缓存)的对象销毁;
    在这里插入图片描述
    注:无法解决Aop代理对象

    情景三(有循环依赖,有Aop)----三级缓存

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    步骤:(待)

    https://blog.csdn.net/lkforce/article/details/97183065
    https://blog.csdn.net/m0_43448868/article/details/113578628
    https://www.bilibili.com/video/BV1ET4y1N7Sp?p=1
    参考链接:
    https://www.nowcoder.com/discuss/747711
    https://blog.csdn.net/qq_36714200/article/details/111240510

    AOP部分

    1.AOP

    面向切面编程,
    主要本质: 对业务逻辑的各个部分进行分离,从而业务逻辑和一些其他非业务逻辑:事务、日志等分隔开,同理降低耦合度,并且代码的复用能力。


    2.静态代理和动态代理

    静态代理:
    对一个类,我们利用其对象来调用其方法,但是我们生成一个代理类,这个代理类作为其访问的接口,并且我们可以在其对象方法前后加上自己的新的逻辑功能,进行增强。— 编译时完成

    动态代理:
    不同于静态代理,我们在运行时进行动态代理类的生成,主要分为两种:
    1)基于JDK
    接口+实现类
    主要是反射实现的,代理类Proxy,主要是三个参数(实现类的类加载器、实现类的接口、实现invocationhandler接口的对象(实现类对象)

    2)基于CGLIB
    没有接口,只有实现类,通过ASM开源包
    对代理对象类的class文件加载进来,通过修改字节码生成子类处理。因此如果被代理类被final关键字所修饰,会失败。
    内部是实现”MethodInterceptor“接口,而这个接口内部获得实现类的元对象,并把它设置为Enhance类的父类,所以这是继承的思想,在其字节码中的指定对象前后加入自己处理逻辑。

    3)对比
    cglib的创建效率低,调用效率高;而spring默认是jdk代理,但是如果没有实现接口,则强制使用CGLib来实现动态代理。


    3.spring的常用设计模式

    1)简单工厂模式—IOC
    2)单例模式—bean
    3)动态代理----AOP


    4.AOP的实现

    在这里插入图片描述

    术语:
    连接点:类中的方法(不用记)
    切入点:这个才有用,真正被增强的方法
    切面:将通知应用到切入点的过程,是一个动作
    通知/增强:实际增强的逻辑部分,自己写的代码部分

    • 类型:前置通知、后置通知、环绕通知、异常通知、最终通知
    • @Before、@AfterReturning、@Around、@AfterThrouing、@After

    注:就是定义好切入点、通知,然后利用切面来将通知加入到切入点上。

    配置:可以通过切入点表达式@PointCut

    代码实现:

    • 引入依赖

      	<dependency>
               <groupId>org.aspectj</groupId>
               <artifactId>aspectjweaver</artifactId>
               <version>1.9.4</version>
           </dependency>
      
    • 1.xml配置实现

      <beans xmlns="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:context="http://www.springframework.org/schema/context"
                 xmlns:aop="http://www.springframework.org/schema/aop"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              http://www.springframework.org/schema/aop/spring-aop.xsd">
          <!--配置aop:需要导入aop的命名空间-->
          <aop:config>
              <!--配置切入点 -->
              <aop:pointcut id="point" expression="execution(* dao.*.*(..))"/>
             <!-- 配置通知点,需要log类实现相关的接口-->
              <aop:advisor advice-ref="log" pointcut-ref="point"/>
          </aop:config>
      
      /*
      Before(方法执行前) :org.apringframework.aop.MethodBeforeAdvice
      AfterReturning(方法返回后) :org.springframework.aop.AfterReturningAdvice
      After-throwing(异常抛出后) :org.springframework.aop.ThrowsAdviceArround
      环绕,即方法前后 :org.aopaliance.intercept.MethodInterceptor
      */
      public class Log implements MethodBeforeAdvice, AfterReturningAdvice,MethodInterceptor  {
      
          public void before(Method method, Object[] objects, Object o) throws Throwable {
              System.out.println("BeforeAdvice方法执行前");
              System.out.println(method.getName()+";"+o.getClass());
          }
      
          public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
              System.out.println("AfterAdvice方法执行前");
              System.out.println(method.getName()+";"+o.getClass());
          }
      
          public Object invoke(MethodInvocation methodInvocation) throws Throwable {
              System.out.println("Roundadvice方法执行前");
              System.out.println(methodInvocation.getArguments()[0]);//可以获取目标方法的参数值
              Object result=methodInvocation.proceed();//调用目标对象的方法
              System.out.println("RoundAdvice方法执行完成了");
              return result;
          }
      
      }
      
    • 2.注解实现

    • xml配置

      <!-- JDK(默认proxy-target-class="false") cglib(proxy-target-class="true")-->
          <aop:aspectj-autoproxy/>
      
      //定义切面
      //定义bean
      @Aspect
      @Component
      public class MyAspect {
          //配置切点,切点的这个方法不需要实现,只是为了给切面的方法作为锚点
          @Pointcut("execution(* testExecution(..))")
          public void anyTestMethod() {}
      
         //**配置前置通知,使用在anyTestMethod上注册的切入点**很重要!!!
         @Before("ric.study.demo.aop.MyAspect .anyTestMethod()")
          public void doAccessCheck(JoinPoint joinPoint) {
              // ... 实现代码
          }
          // returnVal 就是相应方法的返回值
         // 注意可以通过这样去为你的aop方法获得更多的参数打印详细信息,只要是该注解提供的参数都是这样获取
          @AfterReturning(
              pointcut="ric.study.demo.aop.MyAspect .anyTestMethod()",
              returning="returnVal")
          public void doAccessCheck(Object returnVal) {
              //  ... 实现代码
          }
      
          // 这种最灵活,既能做 @Before 的事情,也可以做 @AfterReturning 的事情
          @Around("ric.study.demo.aop.MyAspect .anyTestMethod()")
          public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
             	//  target 方法执行前... 实现代码
              Object retVal = pjp.proceed();
              //  target 方法执行后... 实现代码
              return retVal;
          }
      
      }  
      

    https://zhuanlan.zhihu.com/p/127792838


    5.spring事务的配置

    • 1.编程式事务管理
      编程式事务管理是侵入性事务管理,使用TransactionTemplate或者直接使用PlatformTransactionManager,对于编程式事务管理,Spring推荐使用TransactionTemplate。

    • 2.声明式事务管理
      声明式事务管理建立在AOP之上,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

    • 3.比较
      编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的,而声明式事务不同,声明式事务属于无侵入式,不会影响业务逻辑的实现,只需要在配置文件中做相关的事务规则声明或者通过注解的方式,便可以将事务规则应用到业务逻辑中。
      显然声明式事务管理要优于编程式事务管理,这正是Spring倡导的非侵入式的编程方式。唯一不足的地方就是声明式事务管理的粒度是方法级别,而编程式事务管理是可以到代码块的,但是可以通过提取方法的方式完成声明式事务管理的配置(黑体不懂)


    6.spring事务的传播?

    事务的传播性一般用在事务嵌套的场景,比如一个事务方法里面调用了另外一个事务方法,那么两个方法是各自作为独立的方法提交还是内层的事务合并到外层的事务一起提交,这就是需要事务传播机制的配置来确定怎么样执行
    常用的事务传播机制如下:

    • PROPAGATION_REQUIRED
      Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行
    • PROPAGATION_REQUES_NEW
      该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
    • PROPAGATION_SUPPORT
      如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
    • PROPAGATION_NOT_SUPPORT
      该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
    • PROPAGATION_NEVER
      该传播机制不支持外层事务,即如果外层有事务就抛出异常
    • PROPAGATION_MANDATORY
      与NEVER相反,如果外层没有事务,则抛出异常
    • PROPAGATION_NESTED
      该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。

    传播规则回答了这样一个问题:一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行


    参考链接:
    https://www.cnblogs.com/mseddl/p/11577846.html

    展开全文
  • Spring AOP 和IOC是什么,分别的使用场景 AOP:面向切面编程。 即在一个功能模块中新增其他功能,比方说你要下楼取个快递,你同事对你说帮我也取一下呗,你就顺道取了。在工作中如果系统中有些包类中没有使用AOP,...
  • spring aop和ioc运用场景

    千次阅读 2019-11-21 10:48:35
    @Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean。 <beans> ...
  • 解释什么是SpringIOC AOP
  • IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合。所以,简单来说,Spring是一个轻量级的控制反转(IoC面向切面(AOP)的容器框架。 spring的基本框架主要包含六大模块:DAO、...
  • 关于Spring IOC和AOP的实现原理

    千次阅读 2019-06-28 10:26:04
    Spring框架IOC和AOP的实现原理 1、IOC是指容器控制程序对象之间的关系,而不是我们传统实现中,由程序代码直接操作。控制权由应用代码转到外部容器,控制权的转移是所谓反转。对于Spring而言,就是由Spring来控制...
  • Spring IOCAOP实现原理

    千次阅读 2019-04-21 00:57:43
    IOC(Inversion of Control) (1). IOC(Inversion of Control)是指容器控制程序... 对于Spring而言,就是由Spring来控制对象的生命周期对象之间的关系;IOC还有另外一个名字——“依赖注入(Dependency Injec...
  • IOC(控制反转) 也叫DI(依赖注入),是一种思想,不是一种技术,IOC主张把对象的控制权交由spring,底层实现是反射+工厂方法模式,IOC容器实际上...常见使用场景有事务管理、日志、全局异常处理、用户鉴权; ...
  • 【Java面试】谈谈自己对于 Spring IoC AOP 的理解

    万次阅读 多人点赞 2019-09-10 09:33:24
    IoC 在其他语言中也有应用,并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。 将对象之间的相互依赖关系交给 IoC 容器来...
  • IOC 在其他语言中也有应用,并非 Spring 特有。 IOC 容器是 Spring 用来实现 IOC 的载体, IOC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。 将对象之间的相互依赖关系交给 IOC 容器来管理,并由 ...
  • Spring IOC和AOP 原理彻底搞懂

    万次阅读 多人点赞 2017-01-09 09:16:05
    IOC和AOP原理,Spring事务原理探究,Spring配置文件属性详解,Spring中的代理模式 Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于Spring中。通过使用...
  • SpringIOC和AOP原理

    千次阅读 2019-03-07 13:56:03
    IOC中将对象交给容器管理,你只需要在Spring配置文件中配置对应的Bean以及相关的属性即可,让Spring容器来生成类的实例对象以及管理对象,当Spring容器启动时会自动初始化好已经配置好的bean以及相关属性,当你调用...
  • Spring 的基本应用IoC AOP

    千次阅读 2019-07-25 19:50:42
    对于任何一个 Java 开发人员,Spring 的大名一定如雷贯耳,在行业中可谓是无人不知、无人不晓,说它是 Java 领域第一框架毫不为过。Spring 概念诞生于 2002 年,创始人 Rod Jahnson 在其著作《Expert One-on-One ...
  • Spring IOC和AOP的理解

    2021-09-24 10:25:31
    IOC在其他语言中也有应用,并非Spring特有。IOC容器是Spring用来实现IOC的载体,IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。 将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象...
  • AOP面向方面编程基于IoC,是对OOP的有益补充。 AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单...
  • springIOCAOP使用场景

    千次阅读 2015-06-24 10:23:14
    http://www.infoq.com/cn/articles/Simplifying-Enterprise-Apps 上面说的很清楚!
  • SpringIOC和AOP优势何在?

    千次阅读 2018-04-25 16:01:28
    Spring的核心莫过于IOC和AOP。可以这个说IOC是把生成对象交给Spring代为管理,只需要在Spring里面配置好Beans,在相应的类中通过简单的注解@Autowired来自动装配生成对象,那么为什么不直接new一个对象,这种方式也...
  • 面试官问道这个问题基本上是想知道 是否了解aop 和ioc的基本概念, 以及大体的实现机制等, 因此我们在回答这个问题时应当首相将概念回答一下, 其次就是应用场景 最后在回答下实现方式等基本ok了   1概念: ...
  • 本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java...IoC DI 的区别? 什么是 AOPAOP 解决了什么问题? AOP 为什么叫做切面编程? 首先声明:IoC &.
  • 理解Spring IoCAOP

    2021-01-30 21:39:49
    众所周知的Spring框架是目前很流行的轻量级框架,轻量级框架的重点在于减小了开发的复杂度。...这取决于控制反转(Inversion of Control)面向切面(Asepct-Orentid-Programming)的编程思想的特点。 IOC IOC() ...
  • Spring IoCAOP作用及用法IoC概念配置方式xml配置或者使用@ComponentScan()代替xml配置实例化方式依赖注入方式bean生命周期、作用域Ioc优势AOP的概念、应用场景及配置方式功能快捷键合理的创建标题,有助于目录的...
  • 解读Spring IOC和AOP原理

    万次阅读 2018-03-21 14:51:20
    最近有朋友问到Spring两大特性IOC(控制反转,依赖注入)与AOP(面向切面编程)的原理,希望我能解读一下。(一). IOC控制反转(IOC)与依赖注入(DI)是同一个概念,目的在于降低系统偶尔,将类的实例化工作转交给Spring...
  • SpringAOP和IOC是什么?使用场景有哪些?Spring事务与数据库事务,传播行为,数据库隔离级别 AOP:面向切面编程。 即在一个功能模块中新增其他功能,比方说你要下楼取个快递,你同事对你说帮我也取一下呗,你就...
  • Spring框架IOC和AOP的实现原理与详解

    万次阅读 多人点赞 2018-01-02 21:51:42
    IoC(Inversion of Control)  (1). IoC(Inversion of Control)是指容器控制程序对象... 对于Spring而言,就是由Spring来控制对象的生命周期对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Inj
  • IoC 在其他语言中也有应用,并非 Spirng 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。将对象之间的相互依赖关系交给 IOC 容器来管理,...
  • Spring Ioc和AOP思想

    2020-03-05 11:35:21
    Spring 是分层的 full-stack(全栈)轻量级开源框架,以 IoC AOP 为内核,提供了展现层 SpringMVC 业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架类库(比如整合Mybatis),...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,368
精华内容 11,747
关键字:

springioc和aop的应用场景

spring 订阅