Spring IOP 没用
Spring提供了很多轻量级应用开发实践的工具集合,这些工具集以接口、抽象类、或工具类的形式存在于Spring中。通过使用这些工具集,可以实现应用程序与各种开源技术及框架间的友好整合。比如有关jdbc封装的数据访问工具Spring JDBC,有关编写单元测试的spring test包以及spring-mock,有关访问动态脚本语言的Spring Script,另外还有发送邮件的工具Spring Mail、日程及任务处理工具Spring scheduling等。 可以这么说,大多数企业级应用开发中经常涉及到的一些通用的问题,都可以通过Spring提供的一些实用工具包轻松解决
依赖注入的三种方式:(1)接口注入(2)Construct注入(3)Setter注入
控制反转(IoC)与依赖注入(DI)是同一个概念,引入IOC的目的:(1)脱开、降低类之间的耦合;(2)倡导面向接口编程、实施依赖倒换原则; (3)提高系统可插入、可测试、可修改等特性。
具体做法:(1)将bean之间的依赖关系尽可能地抓换为关联关系;
(2)将对具体类的关联尽可能地转换为对Java interface的关联,而不是与具体的服务对象相关联;
(3)Bean实例具体关联相关Java interface的哪个实现类的实例,在配置信息的元数据中描述;
(4)由IoC组件(或称容器)根据配置信息,实例化具体bean类、将bean之间的依赖关系注入进来。
org.springframework.beans及org.springframework.context包是Spring IoC容器的基础。BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能。ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。 简而言之,BeanFactory提供了配制框架及基本功能,而ApplicationContext则增加了更多支持企业核心内容的功能。ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具备的能力和行为也适用于ApplicationContext。
IoC容器负责容纳bean,并对bean进行管理。在Spring中,BeanFactory是IoC容器的核心接口。它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。Spring为我们提供了许多易用的BeanFactory实现,XmlBeanFactory就是最常用的一个。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
实现化容器:
- Resource resource = new FileSystemResource("beans.xml");
- BeanFactory factory = new XmlBeanFactory(resource);
- ... 或...
- ClassPathResource resource = new ClassPathResource("beans.xml");
- BeanFactory factory = new XmlBeanFactory(resource);
- ... 或...
- ApplicationContext context = new ClassPathXmlApplicationContext(
- new String[] {"applicationContext.xml", "applicationContext-part2.xml"});
- // of course, an ApplicationContext is just a BeanFactory
- BeanFactory factory = (BeanFactory) context;
<beans><import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
BeanFactory和FactoryBean的区别,简而言之,BeanFactory是加载的容器,加载一切的BEAN,而FactoryBean用于创建代理类
AOP全名Aspect-Or+-iented Programming,中文直译为面向切面(方面)编程,当前已经成为一种比较成熟的编程思想,可以用来很好的解决应用系统中分布于各个模块的交叉关注点问题。在轻量级的J2EE中应用开发中,使用AOP来灵活处理一些具有横切性质的系统级服务,如事务处理、安全检查、缓存、对象池管理等,已经成为一种非常适用的解决方案。 AOP中比较重要的概念有:Aspect、JoinPoint、PonitCut、Advice、Introduction、Weave、Target Object、Proxy Object等
引介(Introduction)是指给一个现有类添加方法或字段属性,引介还可以在不改变现有类代码的情况下,让现有的Java类实现新的接口,或者为其指定一个父类从而实现多重继承。相对于增强(Advice)可以动态改变程序的功能或流程来说,引介(Introduction)则用来改变一个类的静态结构。比如我们可以让一个现有为实现java.lang.Cloneable接口,从而可以通过clone()方法复制这个类的实例。
拦截器是用来实现对连接点进行拦截,从而在连接点前或后加入自定义的切面模块功能。在大多数JAVA的AOP框架实现中,都是使用拦截器来实现字段访问及方法调用的拦截(interception)。所用作用于同一个连接点的多个拦截器组成一个连接器链(interceptor chain),链接上的每个拦截器通常会调用下一个拦截器。Spring AOP及JBoos AOP实现都是采用拦截器来实现的。
面向对象编程(OOP)解决问题的重点在于对具体领域模型的抽象,而面向切面编程(AOP)解决问题的关键则在于对关注点的抽象。也就是说,系统中对于一些需要分散在多个不相关的模块中解决的共同问题,则交由AOP来解决;AOP能够使用一种更好的方式来解决OOP不能很好解决的横切关注点问题以及相关的设计难题来实现松散耦合。因此,面向方面编程 (AOP) 提供另外一种关于程序结构的思维完善了OOP,是OOP的一种扩展技术,弥补补了OOP的不足。
AOP概念详解:注意以下实例<aop:开头的AspectJ的概念,Spring没有分的这么细。
— 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现, 然后可以通过@Aspect标注或在applictionContext.xml中进行配置:
<aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2">
— 连接点(Joinpoint):程序执行过程中的行为,如方法的调用或特定的异常被抛出,在代码上有JoinPoint类和ProceedingJoinPoint类,如下所示,可以通过JoinPoint获取很多参数,JoinPoint一般用在Advice实现方法中作为参数传入,ProceedingJoinPoint用于实现围绕Advice的参数传入。 通过下面JoinPoint的接口可以看出通过JoinPoint可以得到代理对象和Target对象。
- package org.aspectj.lang;
- import org.aspectj.lang.reflect.SourceLocation;
- public interface JoinPoint {
- String toString(); //连接点所在位置的相关信息
- String toShortString(); //连接点所在位置的简短相关信息
- String toLongString(); //连接点所在位置的全部相关信息
- Object getThis(); //返回AOP代理对象
- Object getTarget(); //返回目标对象
- Object[] getArgs(); //返回被通知方法参数列表
- Signature getSignature(); //返回当前连接点签名
- SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
- String getKind(); //连接点类型
- StaticPart getStaticPart(); //返回连接点静态部分
- }
- public interface ProceedingJoinPoint extends JoinPoint {
- public Object proceed() throws Throwable;
- public Object proceed(Object[] args) throws Throwable;
- }
— 切入点(Pointcut):指定一个Adivce将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
xml中配置:
<aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
或使用Annoation :@pointcut("execution * transfer(..)")并用一个返回值为void,方法体为空的方法来命名切入点如: private void anyOldTransfer(){}
之后就可以在Advice中引用,如: @AfterReturning(pointcut="anyOldTransfer()", returning="reVal")
- package org.springframework.aop;
- public interface Pointcut {
- ClassFilter getClassFilter();
- MethodMatcher getMethodMatcher();
- Pointcut TRUE = TruePointcut.INSTANCE;
- }
- package org.springframework.aop;
- public interface ClassFilter {
- boolean matches(Class<?> clazz);//如果clazz与我们关注的现象相符时返回true,负责返回false
- ClassFilter TRUE = TrueClassFilter.INSTANCE;//静态参数 如果类型对于要扑捉的Pointcut来说无所谓,可将此参数传递给Pointcut
- }
- package org.springframework.aop;
- public interface MethodMatcher {
- boolean matches(Method method, Class<?> targetClass);
- /**
- * 是否对参数值敏感
- * 如果为false表明匹配时不需要判断参数值(参数值不敏感),称之为StaticMethodMatcher,这时只有
- * matches(Method method, Class<?> targetClass); 被执行,执行结果可以缓存已提高效率。
- * 如果为true表明匹配时需要判断参数值(参数值敏感),称之为DynamicMethodMatcher,这时先执行
- * matches(Method method, Class<?> targetClass);如果返回true,然后再执行
- * boolean matches(Method method, Class<?> targetClass, Object[] args);已做进一步判断
- *
- */
- boolean isRuntime();
- boolean matches(Method method, Class<?> targetClass, Object[] args);
- MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
- }
关于PointCut中使用的execution的说明:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
modifiers-pattern:方法的操作权限
ret-type-pattern:返回值
declaring-type-pattern:方法所在的包
name-pattern:方法名
parm-pattern:参数名
throws-pattern:异常
记忆法则就是Java定义一个方法时的样子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就可以了。
其中,除ret-type-pattern和name-pattern之外,其他都是可选的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。
常见的PointCut结构图:
— 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。Advice中必须用到PointCut
在xml中配置,配置中的method为Aspect实现类中的方法名,使用pointcut自定义或pointcut-ref进行引用已有pointcut
<aop:before pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="authority" />
<aop:after pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" />
<aop:after-returning pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="log" />
<aop:around pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))" method="processTx" />
<aop:after-throwing pointcut-ref="myPointcut" method="doRecovertyActions" throwing="ex" />
或使用Annoation:
@Before("execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterReturning(returning="rvt", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@AfterThrowing(throwing="ex", pointcut="execution(* com.wicresoft.app.service.impl.*.*(..))")
@After("execution(* com.wicresoft.app.service.impl.*.*(..))")
@Around("execution(* com.wicresoft.app.service.impl.*.*(..))")
注意
- AfterReturning 增强处理处理只有在目标方法成功完成后才会被织入。
- After 增强处理不管目标方法如何结束(保存成功完成和遇到异常中止两种情况),它都会被织入。
使用方法拦截器的around通知,需实现接口MethodInterceptor:
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
invoke()方法的MethodInvocation 参数暴露将被调用的方法、目标连接点、AOP代理和传递给被调用方法的参数。 invoke()方法应该返回调用的结果:连接点的返回值。
一个简单的MethodInterceptor实现看起来如下:
- public class DebugInterceptor implements MethodInterceptor {
- public Object invoke(MethodInvocation invocation) throws Throwable {
- System.out.println("Before: invocation=[" + invocation + "]");
- Object rval = invocation.proceed();
- System.out.println("Invocation returned");
- return rval;
- }
- }
注意MethodInvocation的proceed()方法的调用。这个调用会应用到目标连接点的拦截器链中的每一个拦截器。大部分拦截器会调用这个方法,并返回它的返回值。但是, 一个MethodInterceptor,和任何around通知一样,可以返回不同的值或者抛出一个异常,而不调用proceed方法。但是,没有好的原因你要这么做。
Before通知:需实现MethodBeforeAdvice接口
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method m, Object[] args, Object target) throws Throwable;
}
Throw通知,需实现ThrowsAdvice接口
After Returning通知须直线AfterReturningAdvice接口
public interface AfterReturningAdvice extends Advice {
void afterReturning(Object returnValue, Method m, Object[] args, Object target)
throws Throwable;
}
— 引入(Introduction):添加方法或字段到被通知的类,引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。使用introduction要有三个步骤(1)声明新接口(2)创建自己的IntrouductionInterceptor通过Implements IntroductionInterceptor或extends DelegatingIntroductionInterceptor 并同时implements(1)中声明的接口 (3)将新接口和自定义的IntroductionInterceptor配置到DefaultIntroductionAdvisor中,然后将前三者配置到ProxyFactoryBean中。
- public interface IOtherBean {
- public void doOther();
- }
- public class SomeBeanIntroductionInterceptor implements IOtherBean, IntroductionInterceptor {
- public void doOther() {
- System.out.println("doOther!");
- }
- public Object invoke(MethodInvocation invocation) throws Throwable {
- //判断调用的方法是否为指定类中的方法
- if ( implementsInterface(invocation.getMethod().getDeclaringClass()) ) {
- return invocation.getMethod().invoke(this, invocation.getArguments());
- }
- return invocation.proceed();
- }
- /**
- * 判断clazz是否为给定接口IOtherBean的实现
- */
- public boolean implementsInterface(Class clazz) {
- return clazz.isAssignableFrom(IOtherBean.class);
- }
- }
- <!-- 目标对象 -->
- <bean id="someBeanTarget" class="aop.spring.introduction.SomeBeanImpl" />
- <!-- 通知 -->
- <bean id="someBeanAdvice" class="aop.spring.introduction.SomeBeanIntroductionInterceptor" />
- <!-- 通知者,只能以构造器方法注入-->
- <bean id="introductionAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
- <constructor-arg ref="someBeanAdvice" />
- <constructor-arg value="aop.spring.introduction.IOtherBean" />
- </bean>
- <!-- 代理 (将我们的切面织入到目标对象)-->
- <bean id="someBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <!-- 若目标对象实现了代理接口,则可以提供代理接口的配置 -->
- <property name="proxyInterfaces" value="aop.spring.introduction.ISomeBean" />
- <!-- 配置目标对象 -->
- <property name="target" ref="someBeanTarget" />
- <!-- 配置切面 -->
- <property name="interceptorNames">
- <list>
- <value>introductionAdvisor</value>
- </list>
- </property>
- </bean>
— 拦截器(Advisor )常用的有PointCutAdvisor和IntroudtionAdvisor。前者Advisor有PointCut和Advice组成,满足Poincut(指定了哪些方法需要增强),则执行相应的Advice(定义了增强的功能),后者由Introduction构成。PointCutAdvisor主要是根据PointCut中制定的Target Objects的方法在调用(前,后,around,throws, after-return等)时引入新的Aspect中的methods, 而IntroductionAdvisor主要是引入新的接口到Targets对象中。
- public interface PointcutAdvisor {
- Pointcut getPointcut();
- Advice getAdvice();
- }
1、 PointcutAdvisor: Advice和Pointcut,默认实现为DefaultPointcutAdvisor, 还有NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。
其中NameMacthMethodPointCutAdvisor、RegexpMethodPointCutAdvisor 可以对比常用的PointCut类有NameMatchedMethodPointCut和JdkRegexMethodPointCut。
前者需要注入mappedName和advice属性,后者需要注入pattern和advice属性。其中mappedName和pattern是直接配置的值,而advice需要自己实现具体的advice,可见实现advisor的时候,不需要实现PointCut,一般PointCut只需要配置就好了,不需要具体实现类
mappedName指明了要拦截的方法名,pattern按照正则表达式的方法指明了要拦截的方法名,advice定义了一个增强(需要自己实 现MethodBeforeAdvice、 MethodAfterAdvice、ThrowsAdvice、MethodInterceptor接口之 一)。然后在ProxyFactoryBean的拦截器(interceptorNames)中注入这个PointCutAdvisor即可,如上面这个ProxyFactoryBean是一个静态代理,只能代理一个类给加上AOP,那么这个静态代理需要注入有目标对象,目标对象的接口,和interceptorsNames
2、 IntroductionAdvisor :默认实现为DefaultIntroductionAdvisor,这个主要与Introduction有关,可以参考上面的例子
— 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
— AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。如ProxyFactory,ProxyFactoryBean, 下面会进行详细说明
— 编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。将Aspect加入到程序代码的过程,对于Spring AOP,由ProxyFactory或者ProxyFactoryBean负责织入动作。
通过ProxyFactory可以将对符合条件的类调用时添加上Aspect。
或者 可使用XML声明式 ProxyFactoryBean:需要设定 target,interceptorNames(可以是Advice或者Advisor,注意顺序, 对接口代理需设置proxyInterfaces
注意:一个ProxyFactoryBean只能指定一个代理目标,不是很方便,这就产生了自动代理。通过自动代理,可以实现自动为多个目标Bean实现AOP代理、避免客户端直接访问目标Bean(即getBean返回的都是Bean的代理对象)。spring的自动代理是通过BeanPostProcessor实现的,容器载入xml配置后会修改bean为代理Bean,而id不变。
ApplicationContext可以直接检测到定义在容器中的BeanPostProcessor,BeanFactory需要手动添加。
有2种常用的BeanPostProcessor:
1.BeanNameAutoProxyCreator 故名思议,BeanName需要注入的两个属性有BeanNames和interceptorNames
- <bean id="loginBeforeAdvisor" .../>
- <bean id="loginThrowsAdvisor" .../>
- <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
- <!-- 注入目标Bean -->
- <property name="beanNames" value="*Service">
- </property>
- <property name="interceptorNames">
- <list>
- <value>loginBeforeAdvisor</value>
- <value>loginThrowsAdvisor</value>
- </list>
- </property>
- </bean>
2.DefaultAdvisorAutoProxyCreator: DefaultAdvisorAutoProxyCreator和BeanNameAutoProxyCreator不同的是,前者只和Advisor 匹配, 该类实现了BeanPostProcessor接口。当应用上下文读入所有的Bean的配置信息后,该类将扫描上下文,寻找所有的Advisor,他将这些Advisor应用到所有符合切入点的Bean中。所以下面的xml中没有绑定也无需绑定DefaultAdvisorAutoProxyCreator与Advisor的关系。
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
- <bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
- <constructor-arg>
- <value>5000</value>
- </constructor-arg>
- </bean>
- <!-- 使用RegexpMethodPointcutAdvisor来匹配切入点完成个一个Advisor; -->
- <bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
- <property name="pattern">
- <!-- 匹配的名字为方法名-->
- <value>.*buy.*</value>
- </property>
- <property name="advice">
- <ref bean="performanceThresholdInterceptor"/>
- </property>
- </bean>
- <bean id="defaultAdvisorAutoProxyCreator"
- class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
- </beans>
在使用Aonnotation的时候,需要进行在ApplicationContext.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"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/beans/spring-aop-3.0.xsd">
- <!-- 启动对@AspectJ注解的支持 -->
- <aop:aspectj-autoproxy/>
- </beans>
综上,Spring下AOP的配置与实现,BeanNameAutoProxyCreator,DefaultAdvisorAutoProxyCreator已经部分简化了AOP配置,然而还是很繁琐: 首先要编写xxxAdvice类(需要自己实现MethodBeforeAdvice、MethodAfterAdvice、 ThrowsAdvice、MethodInterceptor接口之一),然后还要在xml中配置Advisor,还要在Advisor中注入 Advice,最后还要将Advisor加入ProxyFactoryBean、BeanNameAutoProxyCreator或者 DefaultAdvisorAutoProxyCreator中
。
实际上AOP不止Spring进行了实现,还有AspectJ,后者对AOP中的概念实现比较彻底,可以看上面,而Spring中对AOP的方方面面进行简化,拿上面定义的regexpFilterPointcutAdvisor是一种Advisor包含了PointCut和Advice,而此处的PointCut就是pattern属性的值了,没有特定的PointCut Bean定义,而advice定义了Bean。而其他概念Aspect, JoinPoint都融汇于Advice的实现中即Advisor(MethodBeforeAdvice等和MethodIntector接口的实现类)或IntroductionInterceptor了。
Spring IOP 没用的更多相关文章
- Spring IOP 面向切面编程
Spring IOP 面向切面编程 AOP操作术语 Joinpoint(连接点):所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点.(类里面 ...
- spring源码解析--上
本文是作者原创,版权归作者所有.若要转载,请注明出处. 首先是配置类 package com.lusai.config; import org.springframework.context.anno ...
- 【转】Java开发必须要知道的知识体系
Java Java是一门超高人气编程语言,拥有跨平台.面向对象.泛型编程等特性.在TIOBE编程语言排行榜中,连续夺得第一宝座,而且国内各大知名互联网公司,后端开发首选语言:非Java莫属.今天只是梳 ...
- from: Java开发必须要知道的知识体系
from: https://zhuanlan.zhihu.com/p/21895647 作者:靳洪飞链接:https://zhuanlan.zhihu.com/p/21895647来源:知乎著作权归 ...
- Spring 已看 没用
注解 @Autwired 依赖注入 作用: 自动按照类型注入.当使用注解注入属性时,set方法可以省略.它只能注入其他bean类型.当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在 ...
- 对spring、AOP、IOP的理解 (转)
spring 的优点?1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦2.可以使用容易提供的众多服务,如事务管理,消息服务等3.容器提供单例模式支持4.容器提供了AOP技术,利用它很容易实现如权 ...
- 第二个基础框架 — spring — xml版,没用注解 — 更新完毕
1.什么是spring? 老规矩:百度百科一手 这上面说得太多了,我来提炼一下: spring就是一个轻量级的控制反转( IOC ) 和 面向切面编程( AOP ) 的容量框架.总的来说:本质就是对j ...
- 对Maven、gradle、svn、spring 3.0 fragment、git的想法
1.Maven Maven可以构建项目,采用pom方式配置主项目和其他需要引用的项目.同时可结合spring3.0的新特性web fragment. 从现实出发,特别是对于管理不到位,程序员整体素质 ...
- Spring8:一些常用的Spring Bean扩展接口
前言 Spring是一款非常强大的框架,可以说是几乎所有的企业级Java项目使用了Spring,而Bean又是Spring框架的核心. Spring框架运用了非常多的设计模式,从整体上看,它的设计严格 ...
随机推荐
- Please enable network time synchronisation in system settings
eth区块同步出现这样的WARN: WARN [06-17|13:02:42] System clock seems off by -51.509894715s, which can prevent ...
- nginx location 语法
location 语法location 有”定位”的意思, 根据Uri来进行不同的定位.在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上.比如, 碰到.p ...
- O(1) 快速乘
有一些毒瘤题,数据大小不光会炸\(int\),有时甚至会炸\(long long\).这时一个\(O(1)\)的防爆乘就很重要了 \(a*b%p\)可以转化为\(a*b-[a*b/p]*p\) 这里用 ...
- 《python基础教程(第二版)》学习笔记 文件和素材(第11章)
<python基础教程(第二版)>学习笔记 文件和素材(第11章) 打开文件:open(filename[,mode[,buffering]]) mode是读写文件的模式f=open(r' ...
- HBase常用操作-HBaseUtil
package com.zhen.hbase; import java.io.IOException; import java.util.ArrayList; import java.util.Col ...
- Linux - xshell上传文件报错乱码
xshell上传文件报错乱码,解决方法 rz -be 回车 下载sz filename
- 绘图工具--turtle模块
turtle模块主要使用两个类,一个是TurtleScreen类,表示画布(窗口),用来展示画的位置:一个是Turtle类,用来充当画笔,用来画. 两个类的方法也以同名的函数的形式存在,所以可以以面向 ...
- IpIImage -> CvMat 转换方法
Ipl转为CvMat 一般为这两种方法: 1: /*cvGetMat*/ CvMat matheader; CvMat * mat = cvGetMat(img, &matheader); 2 ...
- LOJ2722 「NOI2018」情报中心
「NOI2018」情报中心 题目描述 C 国和D 国近年来战火纷飞. 最近,C 国成功地渗透进入了D 国的一个城市.这个城市可以抽象成一张有$n$ 个节点,节点之间由$n - 1$ 条双向的边连接的无 ...
- bzoj 3091: 城市旅行 LCT
题目: http://www.lydsy.com/JudgeOnline/problem.php?id=3091 题解: 首先前三个操作就是裸的LCT模板 只考虑第四个操作. 要求我们计算期望,所以我 ...