1. SeataAutoConfiguration 自动配置类的加载
基于SpringBoot的starter机制,在应用上下文启动时,会加载SeataAutoConfiguration自动配置类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=io.seata.spring.boot.autoconfigure.SeataAutoConfiguration
此配置类将会往应用上下文中注册四个组件
从名字就知道,此组件负责扫描@GlobalTransaction
此类的继承关系如下图所示
2. @GlobalTransaction注解扫描
父类 AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor 接口,重写了 postProcessAfterInitialization 方法
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// do checkers
if (!doCheckers(bean, beanName)) {
return bean;
}
try {
synchronized (PROXYED_SET) {
if (PROXYED_SET.contains(beanName)) {
return bean;
}
interceptor = null;
//check TCC proxy
if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
// init tcc fence clean task if enable useTccFence
TCCBeanParserUtils.initTccFenceCleanTask(TCCBeanParserUtils.getRemotingDesc(beanName), applicationContext);
//TCC interceptor, proxy bean of sofa:reference/dubbo:reference, and LocalTCC
interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
(ConfigurationChangeListener)interceptor);
} else {
//很实用的两个工具类
//查找类的原始类 而非代理类
Class serviceInterface = SpringProxyUtils.findTargetClass(bean);
//查找类所有实现的接口
Class[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);
// 类上面是否有GlobalTransactional 注解 方法上面是否有标 GlobalTransactional GlobalLock注解
if (!existsAnnotation(new Class[]{serviceInterface})
// 接口上面是否有GlobalTransactional 注解 方法上面是否有标 GlobalTransactional GlobalLock注解
&& !existsAnnotation(interfacesIfJdk)) {
return bean;
}
//如果有 成员变量 MethodInterceptor interceptor 赋值
if (globalTransactionalInterceptor == null) {
globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
ConfigurationCache.addConfigListener(
ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
(ConfigurationChangeListener)globalTransactionalInterceptor);
}
interceptor = globalTransactionalInterceptor;
}
LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName());
if (!AopUtils.isAopProxy(bean)) {
//当前类没有被AOP代理过
bean = super.wrapIfNecessary(bean, beanName, cacheKey);
} else {
//当前类被AOP代理过
//AdvisedSupport对象是Spring框架中用于支持AOP的核心类之一,它封装了AOP代理的配置信息和运行时状态。
// 通过获取AdvisedSupport对象,可以进一步了解和操作代理对象的AOP配置
AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);
// AdvisedSupport : Advisor 一对多
//Spring AOP 中的 Advisor 是一种拦截器,
// 它可以拦截特定的方法调用,并在方法调用前、后或异常时执行一些特定的操作
//getAdvicesAndAdvisorsForBean 方法将返回我们上一步创建的GlobalTransactionalInterceptor
//buildAdvisors 方法 将 MethodInterceptor 构建成一个 Advisor 用于后续创建代理类
Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));
int pos;
for (Advisor avr : advisor) {
// Find the position based on the advisor's order, and add to advisors by pos
//调整advisor 的位置
pos = findAddSeataAdvisorPosition(advised, avr);
advised.addAdvisor(pos, avr);
}
}
//记录已经代理过的beanName
PROXYED_SET.add(beanName);
//返回当前bean
return bean;
}
} catch (Exception exx) {
throw new RuntimeException(exx);
}
}
创建代理类情况一 :当前bean已经被AOP代理过
通常@GlobalTransation注解标注在业务层,而业务层的bean大多走到这已经被AOP代理过。如果你项目中使用的是MybatisPlus,那么通常会被org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor创建代理类
AdvisedSupport 添加一个Advisor( GlobalTransactionalInterceptor )后,将之前就被代理过的bean返回,你可能会好奇,添加一个 Advisor 就不管了 ? 最终谁来调用呢 ?
class org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
继承了 AspectJAwareAdvisorAutoProxyCreator 继承了 AbstractAdvisorAutoProxyCreator 继承了 AbstractAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor,
将在每个bean实例化后执行 postProcessAfterInitialization 方法,
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
最终将找到 org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor:
protected List findEligibleAdvisors(Class beanClass, String beanName) {
//查找所有的Advisor
List candidateAdvisors = findCandidateAdvisors();
//判断当前bean是否满足Advisor的拦截要求
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
Advisor 你可以理解为绑定了ponitcut的Advice 容器 , BeanFactoryTransactionAttributeSourceAdvisor绑定的为 TransactionAttributeSourcePointcut
方法的匹配规则
@Override
public boolean matches(Method method, Class targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
类的匹配规则
org.springframework.transaction.annotation.SpringTransactionAnnotationParser#isCandidateClass
@Override
public boolean isCandidateClass(Class targetClass) {
//当前类上是否有 Transactional 注解
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
而获取方法是的代码如下
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class, boolean)
for (Class clazz : classes) {
//getAllDeclaredMethods 获取当前类包括父类的所有方法
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
我们使用的MybatisPlus通常业务层的类会继承ServiceImpl,而ServiceImpl类中有不少方法就是标注了@Transactional注解,因此 BeanFactoryTransactionAttributeSourceAdvisor 对当前的业务层bean来说,是满足匹配规则的
回到
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
//拿到 BeanFactoryTransactionAttributeSourceAdvisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理类
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy(Class beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建 ProxyFactory 对象,
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//创建 Advisor 链
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
//设置代理目标类
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建目标代理类
return proxyFactory.getProxy(getProxyClassLoader());
}
通常情况下会使用CGLB进行创建代理类
org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
Class rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class proxySuperClass = rootClass;
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
proxySuperClass = rootClass.getSuperclass();
Class[] additionalInterfaces = rootClass.getInterfaces();
for (Class additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
//设置默认回调函数
Callback[] callbacks = getCallbacks(rootClass);
Class[] types = new Class[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
//默认回调函数匹配规则
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
//增强目标代理类
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
private Callback[] getCallbacks(Class rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
//用于aop的回调函数
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = (isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
}
else {
targetInterceptor = (isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
Callback targetDispatcher = (isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
//6个默认的回调函数
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap<>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
Method method = methods[x];
//将 advisor集合转化为 MethodInterceptor 集合
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(method, x);
}
// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
this.fixedInterceptorOffset = mainCallbacks.length;
}
else {
callbacks = mainCallbacks;
}
return callbacks;
}
看一下callbackFilter 设置的 callback回调规则
public int accept(Method method) {
if (AopUtils.isFinalizeMethod(method)) {
logger.trace("Found finalize() method - using NO_OVERRIDE");
return NO_OVERRIDE; //如果是finalize方法,执行targetInterceptor回调函数,相当于什么都没做
}
//方法是否在Advised接口上声明。如果是,则返回DISPATCH_ADVISED,表示需要回调 advisedDispatcher 函数
if (!this.advised.isOpaque() && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
if (logger.isTraceEnabled()) {
logger.trace("Method is declared on Advised interface: " + method);
}
return DISPATCH_ADVISED;
}
// 检查方法是否为equals()方法或hashCode()方法,如果是,则分别返回INVOKE_EQUALS和INVOKE_HASHCODE,表示需要调用EqualsInterceptor 回调函数或 HashCodeInterceptor 回调函数
if (AopUtils.isEqualsMethod(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Found 'equals' method: " + method);
}
return INVOKE_EQUALS;
}
// We must always calculate hashCode based on the proxy.
if (AopUtils.isHashCodeMethod(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Found 'hashCode' method: " + method);
}
return INVOKE_HASHCODE;
}
//获取目标类
Class targetClass = this.advised.getTargetClass();
// Proxy is not yet available, but that shouldn't matter.
//获取方法拦截器链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
boolean haveAdvice = !chain.isEmpty();
boolean exposeProxy = this.advised.isExposeProxy();
boolean isStatic = this.advised.getTargetSource().isStatic();
boolean isFrozen = this.advised.isFrozen();
//chain 不为空 且未冻结
if (haveAdvice || !isFrozen) {
// If exposing the proxy, then AOP_PROXY must be used.
if (exposeProxy) {
if (logger.isTraceEnabled()) {
logger.trace("Must expose proxy on advised method: " + method);
}
return AOP_PROXY; // 使用aopInterceptor 回调函数
}
// Check to see if we have fixed interceptor to serve this method.
// Else use the AOP_PROXY.
//方法是静态的、代理已被冻结,并且存在固定的拦截器来处理该方法,则返回固定拦截器的索引加上固定拦截器偏移量。这段代码用于判断是否存在固定的拦截器来处理该方法,并返回相应的处理方式。如果存在固定的拦截器,则返回固定拦截器的索引加上偏移量;否则,返回AOP_PROXY,表示需要使用AOP代理进行处理。
if (isStatic && isFrozen && this.fixedInterceptorMap.containsKey(method)) {
if (logger.isTraceEnabled()) {
logger.trace("Method has advice and optimizations are enabled: " + method);
}
// We know that we are optimizing so we can use the FixedStaticChainInterceptors.
int index = this.fixedInterceptorMap.get(method);
return (index + this.fixedInterceptorOffset);
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Unable to apply any optimizations to advised method: " + method);
}
return AOP_PROXY;
}
}
else {
// See if the return type of the method is outside the class hierarchy of the target type.
// If so we know it never needs to have return type massage and can use a dispatcher.
// If the proxy is being exposed, then must use the interceptor the correct one is already
// configured. If the target is not static, then we cannot use a dispatcher because the
// target needs to be explicitly released after the invocation.
if (exposeProxy || !isStatic) {
return INVOKE_TARGET;
}
Class returnType = method.getReturnType();
if (targetClass != null && returnType.isAssignableFrom(targetClass)) {
if (logger.isTraceEnabled()) {
logger.trace("Method return type is assignable from target type and " +
"may therefore return 'this' - using INVOKE_TARGET: " + method);
}
return INVOKE_TARGET;
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Method return type ensures 'this' cannot be returned - " +
"using DISPATCH_TARGET: " + method);
}
return DISPATCH_TARGET;
}
}
}
在回到之前那个问题,AdvisedSupport 添加一个Advisor( GlobalTransactionalInterceptor )后,将之前就被代理过的bean返回,当前bean的业务方法在执行时,就会由callbackFilter匹配上 aopInterceptor 回调函数并执行
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
DynamicAdvisedInterceptor 是 CglibAopProxy 的静态内部类 ,实现了 MethodInterceptor 接口
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class targetClass = (target != null ? target.getClass() : null);
// 获取方法拦截器链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
//拦截器链路调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
//返回值处理
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
}
跟进 org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#proceed
@Override
@Nullable
public Object proceed() throws Throwable {
try {
return super.proceed();
}
catch (RuntimeException ex) {
throw ex;
}
catch (Exception ex) {
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
throw ex;
}
else {
throw new UndeclaredThrowableException(ex);
}
}
}
父类 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 如果当前拦截器链已经是最后一个了 调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// currentInterceptorIndex 从 -1 开始,此时获取下表为0的方法拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
//拦截器在此处调用 注意此处把 this 给传递过去了,每个拦截器在执行完毕后又会调用 this.proceed 进行递归调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
创建代理类情况二 :当前bean已经未被AOP代理
回调 io.seata.spring.annotation.GlobalTransactionScanner#wrapIfNecessary
if (!AopUtils.isAopProxy(bean)) {
//如果当前类未被代理,则调用父类的wrapIfNecessary 方法
bean = super.wrapIfNecessary(bean, beanName, cacheKey);
} else {
AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);
Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));
for (Advisor avr : advisor) {
advised.addAdvisor(0, avr);
}
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
//调用子类 重写的 io.seata.spring.annotation.GlobalTransactionScanner#getAdvicesAndAdvisorsForBean 方法
// 返回 GlobalTransactionalInterceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
调用org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy,
创建 ProxyFactory 对象,设置目标代理类,添加advisors,最终创建代理类,对目标方法进行拦截来增强目标方法
protected Object createProxy(Class beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//构建Advisor[] 用于方法拦截
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
//设置被代理类
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建代理对象 最终底层通过 JDK动态代理或CGILIB代理创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
3.流程图
你可能感兴趣的:(seata源码学习,学习)
iOS安全和逆向系列教程 第16篇:Frida入门与高级应用
自学不成才
iOS安全和逆向系列教程 cocoa macos objective-c
iOS逆向工程专栏第16篇:Frida入门与高级应用前言欢迎来到iOS逆向工程专栏的第16篇文章!在上一篇中,我们探讨了Cycript这一强大的逆向分析工具。今天,我们将深入学习功能更为强大、更为灵活的动态插桩工具——Frida。Frida作为现代iOS逆向工程中最受欢迎的工具之一,其强大的跨平台能力和灵活的JavaScript引擎使得我们能够轻松地分析和修改iOS应用的运行时行为。无论是逆向分析
iOS安全和逆向系列教程 第17篇:探讨ARM64架构与Swift逆向分析技术
自学不成才
iOS安全和逆向系列教程 ios 安全 架构
iOS安全和逆向系列教程第17篇:探讨ARM64架构与Swift逆向分析技术前言欢迎来到iOS安全和逆向系列教程的第17篇。在前面的文章中,我们已经学习了iOS逆向工程的基础知识,以及各种分析工具的使用方法。今天,我们将深入探讨ARM64架构以及Swift语言的逆向分析技术,这两者对于现代iOS应用的逆向工程至关重要。随着Apple全面迁移到ARM64架构和Swift语言的广泛应用,掌握这些技术已
学习prompt
artificiali
prompt
1解释概念中文指令:请借助费曼学习法,以简单的语言解释[特定概念]是什么,并提供一个例子来说明它如何应用。Prompt:PleaseusetheFeynmanLearningTechniquetoexplain[specificconcept]insimplelanguage,andprovideanexampletoillustratehowitapplies.2帕累托法则帮你找到最重要、最具挑
人工智能学习大纲
互联网搬砖老肖
AI 原力计划 工具使用 人工智能 学习
前言人工智能正以惊人的速度发展,其潜力既令人兴奋,也引人深思。它既可能为解决全球性问题带来希望,也可能带来前所未有的挑战。人工智能时代的到来已是不可逆转的趋势,科幻电影中的某些场景或许将成为现实。我对人工智能的研究越深入,就越能感受到它的强大力量。我所担忧的不仅仅是它对就业市场的冲击,更是它可能对人类社会结构带来的深远影响。未来,对人工智能的理解可能像今天对电脑操作的掌握一样重要。掌握人工智能技术
STM32与C51简述
THIRT13N
嵌入式 编程语言 stm32
STM32与C51简述嵌入式开发心得1.关于C51与STM32的说明C51是最早一批进入中国市场的可开发操作的板子/芯片,在早期有着较好的发展方向学习浪潮,早期也有着发达的社区可供交流。随着电子科技的蓬勃发展,STM32逐渐走进了人们的视野。STM32下的几块开发板以其精准得控制,完美得性能,与时俱进的外接设备受到了无数开发者的青睐,至今仍在电子科技的基础产业中起着极其重要的作用,并且发达的社区提
01计算机视觉学习计划
依旧阳光的老码农
计算机视觉 计算机视觉 人工智能
计算机视觉系统学习计划(3-6个月)本计划按照数学→编程→图像处理→机器学习→深度学习→3D视觉→项目实战的顺序,确保从基础到高级,结合理论和实践。第一阶段(第1-2个月):基础夯实✅目标:掌握数学基础、Python/C++编程、基本图像处理1️⃣数学基础(2周)每日2小时线性代数:矩阵运算、特征值分解(推荐《线性代数及其应用》)概率统计:高斯分布、贝叶斯定理微积分:偏导数、梯度下降傅里叶变换:图
决策树 vs 神经网络:何时使用?
HP-Succinum
机器学习 决策树 神经网络 算法
目录1.决策树(DecisionTrees)1.1特点1.2优点1.3缺点1.4适用场景2.神经网络(NeuralNetworks)2.1特点2.2优点2.3缺点2.4适用场景3.何时选择哪种方法?4.结合使用的可能性5.总结在机器学习领域,决策树(DecisionTrees)和神经网络(NeuralNetworks)是两种常见但风格截然不同的算法。它们各自适用于不同类型的问题,本文将介绍它们的特
python-Scrapy爬虫框架介绍(整个数据的流程)
onesalatree
Scrapy框架爬虫 python 软件框架 爬虫 scrapy
python-Scrapy爬虫框架介绍随着在家的线上教育的进行,课程的深入学习,所要学习的内容和作业也在不断的增多,所以没有过多的自己的时间去学习新的爬虫知识,但疫情逐渐的在好转,我也很是期待开学的那一天,毕竟线上教育的效果没有在学校的更为显著,主要是老师们录课很辛苦今天我想和兄弟们分享一下Scrapy爬虫的原理,也是自己最近刚学习的,有什么不足的地方兄弟们可以评论你或者私信喔。Python爬虫的
Conda操作使用教程
迷鹿鹿鹿鹿鹿
conda
声明:该文章仅为学习使用,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!如有侵权,请私信联系本人删帖!Conda操作使用教程Conda是一个开源的包管理和环境管理工具,支持多种编程语言(以Python为主)。它能够帮助用户快速安装、运行和更新软件包,并创建相互隔离的虚拟环境,避免项目之间的依赖冲突。目录Conda的安装基础命令虚拟环境管理包管理环境导出与共享常见问题总结一、安装1
特斯拉FSD系统:自动驾驶的未来
百态老人
人工智能 笔记
FSD系统概述FSD(FullSelf-Driving)系统是特斯拉研发的一套高级自动驾驶技术,旨在实现车辆在各种道路和驾驶场景下的完全自动驾驶。FSD系统通过集成先进的计算机视觉、深度学习、传感器融合等技术,利用车辆上安装的多种传感器和先进的计算机视觉技术,实现对周围环境的感知和理解。特斯拉通过不断收集和分析实际道路数据,持续优化其自动驾驶算法,使得FSD技术的安全性和可靠性得到了大幅提升.FS
FATFS学习(3.1):ff.c(f_mount)
S火星人S
嵌入式:第三方组件移植(fs) 学习 c语言 算法
一:Mount/UnmountaLogicalDrive/*-----------------------------------------------------------------------*//*Mount/UnmountaLogicalDrive*//*-----------------------------------------------------------------
特斯拉FSD不同版本的进化
AI智能涌现深度研究
AI大模型应用入门实战与进阶 java python javascript kotlin golang 架构 人工智能
特斯拉,FSD,自动驾驶,深度学习,计算机视觉,强化学习,神经网络,模型训练1.背景介绍特斯拉自2016年推出Autopilot以来,一直致力于开发全自动驾驶系统,其目标是实现完全无人驾驶,让汽车能够像人类一样感知周围环境,做出安全可靠的驾驶决策。FSD(FullSelf-Driving)是特斯拉自动驾驶系统的最高级别,它旨在实现车辆在任何道路和环境条件下都能安全自主驾驶的能力。FSD的开发是一个
使用 Dlib 库进行人脸检测和人脸识别
萧鼎
python基础到进阶教程 计算机视觉 人工智能 python 人脸识别 人脸检测
使用Dlib库进行人脸检测和人脸识别什么是Dlib?Dlib是一个广泛使用的C++库,提供了多种用于机器学习和计算机视觉的工具。它包含了人脸检测、人脸识别、物体检测、图像处理等功能。Dlib具有高效、易用的Python接口,因此它也被广泛应用于Python中进行深度学习和计算机视觉任务。安装Dlib首先,我们需要在Python环境中安装Dlib库。你可以通过pip进行安装:pipinstalldl
介绍常见的图片分类模型与算法
萧鼎
python基础到进阶教程 算法 分类 数据挖掘
介绍常见的图片分类模型与算法在机器学习和深度学习的领域中,图片分类任务是一个广泛的应用场景。随着深度学习技术的飞速发展,很多强大的图像分类算法和模型已经被提出,广泛应用于从医疗影像到自动驾驶、从人脸识别到图像检索等多个领域。本文将重点介绍多种用于图像分类的经典算法与模型,帮助你了解在图像分类任务中常用的技术。1.传统机器学习模型在深度学习崭露头角之前,传统的机器学习模型是图像分类的主流方法。这些模
Python图形界面开发:PyQt与Tkinter对比分析
萧鼎
python基础到进阶教程 python pyqt 数据库
Python图形界面开发:PyQt与Tkinter对比分析图形用户界面(GUI)是应用程序中不可或缺的一部分,可以帮助用户更直观地与程序进行交互。Python拥有许多开发GUI的库,其中PyQt和Tkinter是最受欢迎的两个选择。本篇博客将从功能、易用性、性能、社区支持、学习曲线等角度对比分析这两个库,并通过一个简单的实战项目帮助你更直观地理解它们的差异。一、PyQt与Tkinter简介1.Py
如何通过卷积神经网络(CNN)有效地提取图像的局部特征,并在CIFAR-10数据集上实现高精度的分类?
浪九天
人工智能理论 python 后端 深度学习 神经网络 人工智能 机器学习 pytorch
目录1.CNN提取图像局部特征的原理2.在CIFAR-10数据集上实现高精度分类的步骤2.1数据准备2.2构建CNN模型2.3定义损失函数和优化器2.4训练模型2.5测试模型3.提高分类精度的技巧卷积神经网络(ConvolutionalNeuralNetwork,CNN)是专门为处理具有网格结构数据(如图像)而设计的深度学习模型,能够有效地提取图像的局部特征。下面将详细介绍如何通过CNN提取图像局
AI大模型在职业教育中的应用解决方案
中年猿人
人工智能 ai 学习
1.引言随着新经济、新技术的加速发展和经济结构的不断调整,职业教育迎来了新的发展机遇与挑战。传统的职业教育模式难以满足日益个性化、多样化的学习需求,同时,技术快速更迭使得职业技能更新频率大幅提高。这些变化要求职业教育能够更加灵活、高效地适应劳动力市场的需求,并为学生提供与时俱进的技能培养。人工智能(AI)作为一种前沿的科技趋势,其大模型技术通过强大的数据处理能力和学习算法,在众多行业中均展现了巨大
FATFS学习(3.4):ff.c(f_read)
S火星人S
嵌入式:第三方组件移植(fs) 学习 c语言 数据库
一:f_readFRESULTf_read(FIL*fp,/*Openfiletoberead*/void*buff,/*Databuffertostorethereaddata*/UINTbtr,/*Numberofbytestoread*/UINT*br/*Numberofbytesread*/){FRESULTres;FATFS*fs;DWORDclst;LBA_tsect;FSIZE_tr
DevOps落地实践点滴和踩坑记录-(1)
xuhss_com
计算机 devops 运维 计算机
优质资源分享学习路线指引(点击解锁)知识定位人群定位Python实战微信订餐小程序进阶级本课程是pythonflask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统记录初衷本人一直在从事企业内DevOps落地实践的工作,走了不少弯路,也努力在想办法解决面临的问题,期间也经历过不少人和事
一分钟教会你如何把 DeepSeek 接入 WPS,开启智能办公新体验!
多模态大模型
wps 人工智能 chatgpt 自然语言处理 产品经理 大模型 deepseek
在数字化办公的时代,如何高效地处理文档、生成创意内容以及进行数据分析,是每一个职场人士的刚需。DeepSeek作为一款强大的AI助手,能够帮助我们快速完成这些任务。而WPS作为国内最受欢迎的办公软件之一,其与DeepSeek的结合,无疑是提升办公效率的绝佳选择。今天,就让我们一起来学习如何将DeepSeek接入WPS,让你的办公效率瞬间提升!一、入门知识点:DeepSeek是什么?DeepSeek
一文读懂!OpenCV 实时人脸识别从 0 到 1,小白也能轻松实操的超详细教程(完整教程及源码)
AI_DL_CODE
opencv 人工智能 计算机视觉 人脸识别
摘要:本文围绕使用OpenCV实现实时人脸识别展开。从环境搭建入手,详细介绍Python及相关库的安装。数据准备环节涵盖收集、标注及预处理步骤。深入阐述特征提取、模型训练方法,包含传统与深度学习方式,还介绍OpenCV预训练模型的使用与评估。详细讲解实时识别过程,包括打开摄像头、逐帧处理及结果显示优化。针对复杂场景,提出光照、姿态、遮挡等问题的解决办法及模型更新维护策略。通过丰富代码示例与解释,助
The Rust Programming Language 学习 (一)
niandb
rust 学习 c++ linux c语言
说明关于参考的教程TheRustProgrammingLanguage是英文版本的由于本人英语水平相当的有限,所以我们这里直接去看翻译好的版本Rust程序设计语言.下面我们将两个地址全部都贴出来.TheRustProgrammingLanguageRust程序设计语言Rust官方文档中文教程教程中提到的一些前置翻译已参照最新的Rust1.58.0版及开发版进行调整,这是目前网上最新的中文版本,最后
国内外算法比赛推荐
AspiringUstcer_1958
C++学习 算法 c++
引言在计算机科学领域,算法比赛是提升编程技能、检验学习成果的绝佳途径。对于C++语言的爱好者来说,选择一个高质量且对C++支持良好的算法比赛至关重要。今天,将从国内外两个维度为大家推荐这类比赛。国际知名算法比赛ACM国际大学生程序设计竞赛(ACM-ICPC)ACM-ICPC是一项在全球范围内极具影响力的大学生算法和编程竞赛,自1970年起举办,历史悠久且规模宏大。参赛队伍由三名大学生组成,需在五小
手把手教你tomcat全部知识点(2)——解决tomcat9w.exe不能使用问题
中二少年学编程
中二少年工具箱 tomcat java
有任何问题,都可以私信博主,共同探讨学习。正文开始前言一、为tomcat创建服务,解决tomcat9w.exe不能使用的问题1.1.创建服务:1.2启动tomcat9w.exe二、tomcat日志简述总结前言上篇文章已经讲解了如何快速启动tomcat,以及启动过程中可能遇到的问题和解决方法。本篇文章更进一步,介绍如何为tomcat创建服务,从而使tomcat可以通过tomcat9w.exe等可视化
第37篇Personalized Federated Learning: A Meta-Learning Approach(perfedavg联邦学习+元学习)2020个性化联邦学习使用Hessian
还不秃顶的计科生
联邦学习 学习
第一部分:解决的问题联邦学习(FL)在多用户协同训练模型时,因数据隐私和通信限制,用户仅与中央服务器交互。传统FL方法得到的全局模型无法适应各用户的异质数据,导致在用户本地数据集上性能不佳因此这篇论文旨在解决联邦学习中模型缺乏个性化的问题第二部分:idea基于模型无关元学习(MAML)框架,提出个性化联邦学习问题的新公式。通过寻找一个初始共享模型,让用户基于自身数据执行少量梯度下降步骤就能快速适应
STM32江科大学习笔记
weixin_38647099
stm32 单片机 学习
STM32江科大学习笔记-制作中...GPIO操作其它的库函数输出流程输出的库函数输出的例子输入流程输入的库函数输入的例子栗子按键开关类1个按键-控制开跟关2个按键-分别控制开跟关按键双击事件按键长按事件外设模块类蜂鸣器OLED屏幕光敏传感器s90G舵机GPIO操作其它的库函数以下是GPIO其它函数/***@brief初始化指定的端口引脚*@paramGPIOx:设置的外设,其中x可以是(A到G)
java取列表a和b的交集_JAVA——两个List集合求交集、并集和差集(去重)模板
FreVision优选
java取列表a和b的交集
关注微信公众号:CodingTechWork,一起学习进步。引言经常遇到一些集合类之间的过滤数据、求合集之类的问题,在此以List为例,毕竟在数据库中取数据后,我们使用比较多的是List集合进行操作。模板代码publicstaticvoidmain(String[]args){ListstringList=newArrayList(Arrays.asList("a,b,c,d,e,f,g,h".s
弹性算力革命:企业级GPU云服务如何重构AI与图形处理的效能边界
企业级GPU云服务是一种面向企业用户,基于云计算技术,将强大的图形处理器(GPU)资源以服务的形式提供给企业的创新模式。通过这种模式,企业无需自行购置、安装和维护昂贵的GPU硬件设备,只需按需从云端获取GPU计算资源,就能满足自身多样化的业务需求。随着人工智能、大数据、深度学习、虚拟现实以及高性能计算等前沿技术在各行业的深入渗透,企业对于大规模并行计算能力的要求越来越高。GPU凭借其卓越的并行计算
弹性算力革命:企业级GPU云服务如何重构AI与图形处理的效能边界
企业级GPU云服务是一种面向企业用户,基于云计算技术,将强大的图形处理器(GPU)资源以服务的形式提供给企业的创新模式。通过这种模式,企业无需自行购置、安装和维护昂贵的GPU硬件设备,只需按需从云端获取GPU计算资源,就能满足自身多样化的业务需求。随着人工智能、大数据、深度学习、虚拟现实以及高性能计算等前沿技术在各行业的深入渗透,企业对于大规模并行计算能力的要求越来越高。GPU凭借其卓越的并行计算
量化投资与算法交易
AI天才研究院
Python实战 自然语言处理 人工智能 语言模型 编程实践 开发语言 架构设计
作者:禅与计算机程序设计艺术1.简介量化投资(Quantitativeinvestment)和算法交易(AlgorithmicTrading),两者是近几年兴起的两个热门词汇。市场对这两个词汇的认识也是逐渐加深。在过去几年里,人们普遍认为,算法交易和机器学习结合是未来股票、期货等金融产品的必然趋势。机器学习是由多个数据源(如财务报表、交易历史数据、社交网络数据等)自动分析生成的模型,能够预测出股价
VMware Workstation 11 或者 VMware Player 7安装MAC OS X 10.10 Yosemite
iwindyforest
vmware mac os 10.10 workstation player
最近尝试了下VMware下安装MacOS 系统,
安装过程中发现网上可供参考的文章都是VMware Workstation 10以下, MacOS X 10.9以下的文章,
只能提供大概的思路, 但是实际安装起来由于版本问题, 走了不少弯路, 所以我尝试写以下总结, 希望能给有兴趣安装OSX的人提供一点帮助。
写在前面的话:
其实安装好后发现, 由于我的th
关于《基于模型驱动的B/S在线开发平台》源代码开源的疑虑?
deathwknight
JavaScript java 框架
本人从学习Java开发到现在已有10年整,从一个要自学 java买成javascript的小菜鸟,成长为只会java和javascript语言的老菜鸟(个人邮箱:deathwknight@163.com)
一路走来,跌跌撞撞。用自己的三年多业余时间,瞎搞一个小东西(基于模型驱动的B/S在线开发平台,非MVC框架、非代码生成)。希望与大家一起分享,同时有许些疑虑,希望有人可以交流下
平台
如何把maven项目转成web项目
Kai_Ge
maven MyEclipse
创建Web工程,使用eclipse ee创建maven web工程 1.右键项目,选择Project Facets,点击Convert to faceted from 2.更改Dynamic Web Module的Version为2.5.(3.0为Java7的,Tomcat6不支持). 如果提示错误,可能需要在Java Compiler设置Compiler compl
主管???
Array_06
工作
转载:http://www.blogjava.net/fastzch/archive/2010/11/25/339054.html
很久以前跟同事参加的培训,同事整理得很详细,必须得转!
前段时间,公司有组织中高阶主管及其培养干部进行了为期三天的管理训练培训。三天的课程下来,虽然内容较多,因对老师三天来的课程内容深有感触,故借着整理学习心得的机会,将三天来的培训课程做了一个
python内置函数大全
2002wmj
python
最近一直在看python的document,打算在基础方面重点看一下python的keyword、Build-in Function、Build-in Constants、Build-in Types、Build-in Exception这四个方面,其实在看的时候发现整个《The Python Standard Library》章节都是很不错的,其中描述了很多不错的主题。先把Build-in Fu
JSP页面通过JQUERY合并行
357029540
JavaScript jquery
在写程序的过程中我们难免会遇到在页面上合并单元行的情况,如图所示
如果对于会的同学可能很简单,但是对没有思路的同学来说还是比较麻烦的,提供一下用JQUERY实现的参考代码
function mergeCell(){
var trs = $("#table tr");
&nb
Java基础
冰天百华
java基础
学习函数式编程
package base;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
// Integer a = 4;
// Double aa = (double)a / 100000;
// Decimal
unix时间戳相互转换
adminjun
转换 unix 时间戳
如何在不同编程语言中获取现在的Unix时间戳(Unix timestamp)? Java time JavaScript Math.round(new Date().getTime()/1000)
getTime()返回数值的单位是毫秒 Microsoft .NET / C# epoch = (DateTime.Now.ToUniversalTime().Ticks - 62135
作为一个合格程序员该做的事
aijuans
程序员
作为一个合格程序员每天该做的事 1、总结自己一天任务的完成情况 最好的方式是写工作日志,把自己今天完成了什么事情,遇见了什么问题都记录下来,日后翻看好处多多
2、考虑自己明天应该做的主要工作 把明天要做的事情列出来,并按照优先级排列,第二天应该把自己效率最高的时间分配给最重要的工作
3、考虑自己一天工作中失误的地方,并想出避免下一次再犯的方法 出错不要紧,最重
由html5视频播放引发的总结
ayaoxinchao
html5 视频 video
前言
项目中存在视频播放的功能,前期设计是以flash播放器播放视频的。但是现在由于需要兼容苹果的设备,必须采用html5的方式来播放视频。我就出于兴趣对html5播放视频做了简单的了解,不了解不知道,水真是很深。本文所记录的知识一些浅尝辄止的知识,说起来很惭愧。
视频结构
本该直接介绍html5的<video>的,但鉴于本人对视频
解决httpclient访问自签名https报javax.net.ssl.SSLHandshakeException: sun.security.validat
bewithme
httpclient
如果你构建了一个https协议的站点,而此站点的安全证书并不是合法的第三方证书颁发机构所签发,那么你用httpclient去访问此站点会报如下错误
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path bu
Jedis连接池的入门级使用
bijian1013
redis redis数据库 jedis
Jedis连接池操作步骤如下:
a.获取Jedis实例需要从JedisPool中获取;
b.用完Jedis实例需要返还给JedisPool;
c.如果Jedis在使用过程中出错,则也需要还给JedisPool;
packag
变与不变
bingyingao
不变 变 亲情永恒
变与不变
周末骑车转到了五年前租住的小区,曾经最爱吃的西北面馆、江西水饺、手工拉面早已不在,
各种店铺都换了好几茬,这些是变的。
三年前还很流行的一款手机在今天看起来已经落后的不像样子。
三年前还运行的好好的一家公司,今天也已经不复存在。
一座座高楼拔地而起,
【Scala十】Scala核心四:集合框架之List
bit1129
scala
Spark的RDD作为一个分布式不可变的数据集合,它提供的转换操作,很多是借鉴于Scala的集合框架提供的一些函数,因此,有必要对Scala的集合进行详细的了解
1. 泛型集合都是协变的,对于List而言,如果B是A的子类,那么List[B]也是List[A]的子类,即可以把List[B]的实例赋值给List[A]变量
2. 给变量赋值(注意val关键字,a,b
Nested Functions in C
bookjovi
c closure
Nested Functions 又称closure,属于functional language中的概念,一直以为C中是不支持closure的,现在看来我错了,不过C标准中是不支持的,而GCC支持。
既然GCC支持了closure,那么 lexical scoping自然也支持了,同时在C中label也是可以在nested functions中自由跳转的
Java-Collections Framework学习与总结-WeakHashMap
BrokenDreams
Collections
总结这个类之前,首先看一下Java引用的相关知识。Java的引用分为四种:强引用、软引用、弱引用和虚引用。
强引用:就是常见的代码中的引用,如Object o = new Object();存在强引用的对象不会被垃圾收集
读《研磨设计模式》-代码笔记-解释器模式-Interpret
bylijinnan
java 设计模式
声明: 本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客http://chjavach.iteye.com/
package design.pattern;
/*
* 解释器(Interpreter)模式的意图是可以按照自己定义的组合规则集合来组合可执行对象
*
* 代码示例实现XML里面1.读取单个元素的值 2.读取单个属性的值
* 多
After Effects操作&快捷键
cherishLC
After Effects
1、快捷键官方文档
中文版:https://helpx.adobe.com/cn/after-effects/using/keyboard-shortcuts-reference.html
英文版:https://helpx.adobe.com/after-effects/using/keyboard-shortcuts-reference.html
2、常用快捷键
Maven 常用命令
crabdave
maven
Maven 常用命令
mvn archetype:generate
mvn install
mvn clean
mvn clean complie
mvn clean test
mvn clean install
mvn clean package
mvn test
mvn package
mvn site
mvn dependency:res
shell bad substitution
daizj
shell 脚本
#!/bin/sh
/data/script/common/run_cmd.exp 192.168.13.168 "impala-shell -islave4 -q 'insert OVERWRITE table imeis.${tableName} select ${selectFields}, ds, fnv_hash(concat(cast(ds as string), im
Java SE 第二讲(原生数据类型 Primitive Data Type)
dcj3sjt126com
java
Java SE 第二讲:
1. Windows: notepad, editplus, ultraedit, gvim
Linux: vi, vim, gedit
2. Java 中的数据类型分为两大类:
1)原生数据类型 (Primitive Data Type)
2)引用类型(对象类型) (R
CGridView中实现批量删除
dcj3sjt126com
PHP yii
1,CGridView中的columns添加
array(
'selectableRows' => 2,
'footer' => '<button type="button" onclick="GetCheckbox();" style=&
Java中泛型的各种使用
dyy_gusi
java 泛型
Java中的泛型的使用:1.普通的泛型使用
在使用类的时候后面的<>中的类型就是我们确定的类型。
public class MyClass1<T> {//此处定义的泛型是T
private T var;
public T getVar() {
return var;
}
public void setVa
Web开发技术十年发展历程
gcq511120594
Web 浏览器 数据挖掘
回顾web开发技术这十年发展历程:
Ajax
03年的时候我上六年级,那时候网吧刚在小县城的角落萌生。传奇,大话西游第一代网游一时风靡。我抱着试一试的心态给了网吧老板两块钱想申请个号玩玩,然后接下来的一个小时我一直在,注,册,账,号。
彼时网吧用的512k的带宽,注册的时候,填了一堆信息,提交,页面跳转,嘣,”您填写的信息有误,请重填”。然后跳转回注册页面,以此循环。我现在时常想,如果当时a
openSession()与getCurrentSession()区别:
hetongfei
java DAO Hibernate
来自 http://blog.csdn.net/dy511/article/details/6166134
1.getCurrentSession创建的session会和绑定到当前线程,而openSession不会。
2. getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭。
这里getCurrentSession本地事务(本地
第一章 安装Nginx+Lua开发环境
jinnianshilongnian
nginx lua openresty
首先我们选择使用OpenResty,其是由Nginx核心加很多第三方模块组成,其最大的亮点是默认集成了Lua开发环境,使得Nginx可以作为一个Web Server使用。借助于Nginx的事件驱动模型和非阻塞IO,可以实现高性能的Web应用程序。而且OpenResty提供了大量组件如Mysql、Redis、Memcached等等,使在Nginx上开发Web应用更方便更简单。目前在京东如实时价格、秒
HSQLDB In-Process方式访问内存数据库
liyonghui160com
HSQLDB一大特色就是能够在内存中建立数据库,当然它也能将这些内存数据库保存到文件中以便实现真正的持久化。
先睹为快!
下面是一个In-Process方式访问内存数据库的代码示例:
下面代码需要引入hsqldb.jar包 (hsqldb-2.2.8)
import java.s
Java线程的5个使用技巧
pda158
java 数据结构
Java线程有哪些不太为人所知的技巧与用法? 萝卜白菜各有所爱。像我就喜欢Java。学无止境,这也是我喜欢它的一个原因。日常
工作中你所用到的工具,通常都有些你从来没有了解过的东西,比方说某个方法或者是一些有趣的用法。比如说线程。没错,就是线程。或者确切说是Thread这个类。当我们在构建高可扩展性系统的时候,通常会面临各种各样的并发编程的问题,不过我们现在所要讲的可能会略有不同。
开发资源大整合:编程语言篇——JavaScript(1)
shoothao
JavaScript
概述:本系列的资源整合来自于github中各个领域的大牛,来收藏你感兴趣的东西吧。
程序包管理器
管理javascript库并提供对这些库的快速使用与打包的服务。
Bower - 用于web的程序包管理。
component - 用于客户端的程序包管理,构建更好的web应用程序。
spm - 全新的静态的文件包管
避免使用终结函数
vahoa.ma
java jvm C++
终结函数(finalizer)通常是不可预测的,常常也是很危险的,一般情况下不是必要的。使用终结函数会导致不稳定的行为、更差的性能,以及带来移植性问题。不要把终结函数当做C++中的析构函数(destructors)的对应物。
我自己总结了一下这一条的综合性结论是这样的:
1)在涉及使用资源,使用完毕后要释放资源的情形下,首先要用一个显示的方