国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

ホームページ Java &#&面接の質(zhì)問 Java のインタビューの質(zhì)問: 循環(huán)依存関係とは何か知っていますか? Spring は循環(huán)依存関係をどのように解決するのでしょうか?

Java のインタビューの質(zhì)問: 循環(huán)依存関係とは何か知っていますか? Spring は循環(huán)依存関係をどのように解決するのでしょうか?

Jan 08, 2021 am 10:33 AM
java spring 循環(huán)依存関係 インタビュー

Java のインタビューの質(zhì)問: 循環(huán)依存関係とは何か知っていますか? Spring は循環(huán)依存関係をどのように解決するのでしょうか?

まず、循環(huán)依存関係とは何かについてご紹介します。

(學(xué)習(xí)ビデオ共有: java ビデオ チュートリアル)

いわゆる循環(huán)依存関係とは、A が B に依存し、同時に B が A に依存することです。 2 つの間の依存関係が形成され、リングが形成されます。これは、通常、不適切なエンコードによって発生します。 Spring はプロパティの循環(huán)依存性の問題のみを解決できますが、コンストラクターの循環(huán)依存性の問題は解決できません。この問題には解決策がないためです。

次に、最初にデモを作成して、Spring がプロパティの循環(huán)依存関係の問題をどのように処理するかをデモンストレーションします。

トークは安いです。コードを見せてください。

ステップ 1: プライベート プロパティ コンポーネント B を持つクラス ComponentA を定義します。

package com.tech.ioc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author 君戰(zhàn)
 * **/
@Component
public class ComponentA {

	@Autowired
	private ComponentB componentB;

	public void say(){
		componentB.say();
	}

}

ステップ 2: ComponentA に依存するクラス ComponentB を定義します。そして、データの印刷を容易にするためのsayメソッドを定義します。

package com.tech.ioc;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * @author 君戰(zhàn)
 * **/
@Component
public class ComponentB {

	@Autowired
	private ComponentA componentA;

	public void say(){
		System.out.println("componentA field " + componentA);
		System.out.println(this.getClass().getName() + " -----> say()");
	}

}

3 番目のステップ: 焦點を當て、Spring の循環(huán)依存関係の基礎(chǔ)となる処理を模倣するクラス -SimpleContainer を作成します。このコードを理解していれば、循環(huán)依存関係を処理する Spring のロジックを理解するのが非常に簡単になります。

package com.tech.ioc;

import java.beans.Introspector;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 演示Spring中循環(huán)依賴是如何處理的,只是個簡版,真實的Spring依賴處理遠比這個復(fù)雜。
 * 但大體思路都相同。另外這個Demo很多情況都未考慮,例如線程安全問題,僅供參考。
 * @author 君戰(zhàn)
 *
 * **/
public class SimpleContainer {

	/***
	 * 用于存放完全初始化好的Bean,Bean處于就緒狀態(tài)
	 * 這個Map定義和Spring中一級緩存命名一致
	 * */
	private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

	/***
	 * 用于存放剛創(chuàng)建出來的Bean,其屬性還沒有處理,因此存放在該緩存中的Bean還不可用。
	 * 這個Map定義和Spring中三級緩存命名一致
	 * */
	private final Map<String, Object> singletonFactories = new HashMap<>(16);


	public static void main(String[] args) {
		SimpleContainer container = new SimpleContainer();
		ComponentA componentA = container.getBean(ComponentA.class);
		componentA.say();
	}

	public <T> T getBean(Class<T> beanClass) {
		String beanName = this.getBeanName(beanClass);
		// 首先根據(jù)beanName從緩存中獲取Bean實例
		Object bean = this.getSingleton(beanName);
		if (bean == null) {
			// 如果未獲取到Bean實例,則創(chuàng)建Bean實例
			return createBean(beanClass, beanName);
		}
		return (T) bean;
	}
	/***
	 * 從一級緩存和二級緩存中根據(jù)beanName來獲取Bean實例,可能為空
	 * */
	private Object getSingleton(String beanName) {
		// 首先嘗試從一級緩存中獲取
		Object instance = singletonObjects.get(beanName);
		if (instance == null) { // Spring 之所以能解決循環(huán)依賴問題,也是靠著這個三級緩存--singletonFactories
			instance = singletonFactories.get(beanName);
		}
		return instance;
	}

	/***
	 * 創(chuàng)建指定Class的實例,返回完全狀態(tài)的Bean(屬性可用)
	 *
	 * */
	private <T> T createBean(Class<T> beanClass, String beanName) {
		try {
			Constructor<T> constructor = beanClass.getDeclaredConstructor();
			T instance = constructor.newInstance();
			// 先將剛創(chuàng)建好的實例存放到三級緩存中,如果沒有這一步,Spring 也無法解決三級緩存
			singletonFactories.put(beanName, instance);
			Field[] fields = beanClass.getDeclaredFields();
			for (Field field : fields) {
				Class<?> fieldType = field.getType();
				field.setAccessible(true); 
				// 精髓是這里又調(diào)用了getBean方法,例如正在處理ComponentA.componentB屬性,
				// 執(zhí)行到這里時就會去實例化ComponentB。因為在getBean方法首先去查緩存,
				// 而一級緩存和三級緩存中沒有ComponentB實例數(shù)據(jù),所以又會調(diào)用到當前方法,
				// 而在處理ComponentB.componentA屬性時,又去調(diào)用getBean方法去緩存中查找,
				// 因為在前面我們將ComponentA實例放入到了三級緩存,因此可以找到。
				// 所以ComponentB的實例化結(jié)束,方法出棧,返回到實例化ComponentA的方法棧中,
				// 這時ComponentB已經(jīng)初始化完成,因此ComponentA.componentB屬性賦值成功!
				field.set(instance, this.getBean(fieldType));
			}
			// 最后再將初始化好的Bean設(shè)置到一級緩存中。
			singletonObjects.put(beanName, instance);
			return instance;
		} catch (Exception e) {
			e.printStackTrace();
		}
		throw new IllegalArgumentException();
	}

	/**
	 * 將類名小寫作為beanName,Spring底層實現(xiàn)和這個差不多,也是使用javaBeans的
	 * {@linkplain Introspector#decapitalize(String)}
	 **/
	private String getBeanName(Class<?> clazz) {
		String clazzName = clazz.getName();
		int index = clazzName.lastIndexOf(".");
		String className = clazzName.substring(index);
		return Introspector.decapitalize(className);
	}
}

生徒全員が上記のコードを読んで理解できたら、Spring の循環(huán)依存問題の実際のソース コード分析を?qū)g行します。もう一度読むのは簡単だと思います。

基礎(chǔ)となるソース コードの分析

分析は、AbstractBeanFactory の doGetBean メソッドから始まります。ご覧のとおり、transformedBeanName はこのメソッドで最初に呼び出されます (実際には BeanName の問題に対処するため)。これは私たち自身で作成した getBeanName メソッドと同じ効果がありますが、FactoryBean とエイリアスの問題があるため、Spring はこれをこれよりもはるかに複雑だと考えています。 。

// AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object bean;

		// ?。。≈攸c是這里,首先從緩存中beanName來獲取對應(yīng)的Bean。
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			// 執(zhí)行到這里說明緩存中存在指定beanName的Bean實例,getObjectForBeanInstance是用來處理獲取到的Bean是FactoryBean問題
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		else {
			try {
				// 刪除與本次分析無關(guān)代碼....
				// 如果是單例Bean,則通過調(diào)用createBean方法進行創(chuàng)建
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						} catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
				
				}	
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
		return (T) bean;
	}

getSingleton メソッドにはオーバーロードされたメソッドがあります。オーバーロードされた getSingleton メソッドがここで呼び出されます。この値により初期 Bean の公開が許可されるかどうかが決定されるため、ここに渡されるブール パラメーター値は true であることに注意してください。

// DefaultSingletonBeanRegistry#getSingleton
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}
// DefaultSingletonBeanRegistry#getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 首先從一級緩存中獲取
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 如果一級緩存中未獲取到,再從二級緩存中獲取
			singletonObject = this.earlySingletonObjects.get(beanName);
			// 如果未從二級緩存中獲取到并且allowEarlyReference值為true(前面?zhèn)鞯臑閠rue)
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
				   //Double Check 
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							// 最后嘗試去三級緩存中獲取
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								// 保存到二級緩存
								this.earlySingletonObjects.put(beanName, singletonObject);
								// 從三級緩存中移除
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

(面接の質(zhì)問の詳細については、java 面接の質(zhì)問と回答 をご覧ください)

わかりました。Spring がキャッシュから Bean インスタンスを取得する方法を読んだ後、 creatBean メソッドが Bean を作成する方法を見てください

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	// 刪除與本次分析無關(guān)的代碼...
	try {// createBean方法底層是通過調(diào)用doCreateBean來完成Bean創(chuàng)建的。
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean &#39;" + beanName + "&#39;");
		}
		return beanInstance;
	} catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		throw ex;
	} catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
}
// AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 創(chuàng)建Bean實例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		// 如果允許當前Bean早期曝光。只要Bean是單例的并且allowCircularReferences 屬性為true(默認為true)
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			// 這里調(diào)用了addSingletonFactory方法將剛創(chuàng)建好的Bean保存到了三級緩存中。
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// 刪除與本次分析無關(guān)的代碼.....
		Object exposedObject = bean;
		try {// Bean屬性填充
			populateBean(beanName, mbd, instanceWrapper);
			// 初始化Bean,熟知的Aware接口、InitializingBean接口.....都是在這里調(diào)用
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		} catch (Throwable ex) {
			
		}
		// 刪除與本次分析無關(guān)的代碼.....
		return exposedObject;
	}

まず、addSingletonFactory メソッドを分析します。これは、このメソッドでは Bean が 3 次キャッシュに保存されるためです。

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(singletonFactory, "Singleton factory must not be null");
	synchronized (this.singletonObjects) {
		// 如果一級緩存中不存在指定beanName的key
		if (!this.singletonObjects.containsKey(beanName)) {
			// 將剛創(chuàng)建好的Bean實例保存到三級緩存中
			this.singletonFactories.put(beanName, singletonFactory);
			// 從二級緩存中移除。
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}
}

処理 Bean の依存関係の注入は、populateBean メソッドによって完了しますが、実行リンク全體が長すぎるため、ここでは説明しません。IoC コンテナーがそれをステップで呼び出す方法についてのみ説明します。依存関係を処理するときに getBean メソッドを段階的に実行するため、フィールド インジェクションを処理するために獨自に作成したロジックと一致します。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	// 刪除與本次分析無關(guān)代碼...
	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		// 遍歷所有已注冊的BeanPostProcessor接口實現(xiàn)類,如果實現(xiàn)類是InstantiationAwareBeanPostProcessor接口類型的,調(diào)用其postProcessProperties方法。
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				// 刪除與本次分析無關(guān)代碼...
				pvs = pvsToUse;
			}
		}
		// 刪除與本次分析無關(guān)代碼...
	}
	
}

Spring では、@Autowired アノテーションは AutowiredAnnotationBeanPostProcessor クラスによって処理され、@Resource アノテーションは CommonAnnotationBeanPostProcessor クラスによって処理されます。どちらのクラスも InstantiationAwareBeanPostProcessor インターフェイスを?qū)g裝し、オーバーライドされた postProcessProperties メソッドで完了します。 。ここでは @Autowired アノテーションの処理を分析します。

// AutowiredAnnotationBeanPostProcessor#postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 根據(jù)beanName以及bean的class去查找Bean的依賴元數(shù)據(jù)-InjectionMetadata 
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {// 調(diào)用inject方法
			metadata.inject(bean, beanName, pvs);
		} catch (BeanCreationException ex) {
			throw ex;
		} catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

InjectionMetadata の inject メソッドで、現(xiàn)在の Bean の処理が必要な依存要素 (InjectedElement) をすべて取得します。これはコレクションであり、コレクションを走査して、各依存関係注入の inject メソッドを呼び出します。要素。

// InjectionMetadata#inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// 獲取當前Bean所有的依賴注入元素(可能是方法,也可能是字段)
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		// 如果當前Bean的依賴注入項不為空,遍歷該依賴注入元素
		for (InjectedElement element : elementsToIterate) {
			// 調(diào)用每一個依賴注入元素的inject方法。
			element.inject(target, beanName, pvs);
		}
	}
}

AutowiredAnnotationBeanPostProcessor クラスには 2 つの內(nèi)部クラスが定義されています。AutowiredFieldElement と AutowiredMethodElement は InjectedElement から継承され、それぞれフィールド インジェクションとメソッド インジェクションに対応します。

Java のインタビューの質(zhì)問: 循環(huán)依存関係とは何か知っていますか? Spring は循環(huán)依存関係をどのように解決するのでしょうか?

一般的に使用されるフィールド インジェクションを例に挙げます。AutowiredFieldElement の inject メソッドでは、まず現(xiàn)在のフィールドが処理済みかどうかを確認します。処理済みの場合は、それ以外の場合は、BeanFactory のsolveDependency メソッドを呼び出して依存関係を処理します。

// AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Field field = (Field) this.member;
		Object value;
		if (this.cached) {// 如果當前字段已經(jīng)被處理過,直接從緩存中獲取
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		} else {
			// 構(gòu)建依賴描述符
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {// 調(diào)用BeanFactory的resolveDependency來解析依賴
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			} catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			// 刪除與本次分析無關(guān)代碼....
		}
		if (value != null) {
			// 通過反射來對屬性進行賦值
			ReflectionUtils.makeAccessible(field);
			field.set(bean, value);
		}
	}
}

DefaultListableBeanFactory に実裝されたsolveDependency メソッドは、最終的に doResolveDependency メソッドを呼び出して依存関係解決関數(shù)を完了します。 Spring ソース コードに do メソッドがある場合、このメソッドが実際に作業(yè)を?qū)g行する方法になります。

// DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		// .....
		// 如果在字段(方法)上添加了@Lazy注解,那么在這里將不會真正的去解析依賴
		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
				descriptor, requestingBeanName);
		if (result == null) {
			// 如果未添加@Lazy注解,那么則調(diào)用doResolveDependency方法來解析依賴
			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
		}
		return result;
}
// DefaultListableBeanFactory#doResolveDependency
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

	//.....
	try {
		// 根據(jù)名稱以及類型查找合適的依賴
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		if (matchingBeans.isEmpty()) {// 如果未找到相關(guān)依賴
			if (isRequired(descriptor)) { // 如果該依賴是必須的(例如@Autowired的required屬性),直接拋出異常
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;
		// 如果查找到的依賴多于一個,例如某個接口存在多個實現(xiàn)類,并且多個實現(xiàn)類都注冊到IoC容器中。
		if (matchingBeans.size() > 1) {// 決定使用哪一個實現(xiàn)類,@Primary等方式都是在這里完成
			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
					return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
				} else { 
					return null;
				}
			}
			instanceCandidate = matchingBeans.get(autowiredBeanName);
		} else {
			// We have exactly one match.
			Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
			autowiredBeanName = entry.getKey();
			instanceCandidate = entry.getValue();
		}

		if (autowiredBeanNames != null) {
			autowiredBeanNames.add(autowiredBeanName);
		}
		// 如果查找到的依賴是某個類的Class(通常如此),而不是實例,
		//調(diào)用描述符的方法來根據(jù)類型resolveCandidate方法來獲取該類型的實例。
		if (instanceCandidate instanceof Class) {
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		//...
}

依存関係記述子のresolveCandidateメソッドでは、BeanFactoryのgetBeanメソッドを呼び出すことで依存Beanインスタンスの取得が完了します。

// DependencyDescriptor#resolveCandidate
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
			throws BeansException {

	return beanFactory.getBean(beanName);
}

getBean メソッドの実裝では、やはり doGetBean メソッドを呼び出すことで完了します。これは、私たちが自分で書いた依存関係の処理と基本的に同じですが、自分で書いたものは比較的単純で、Spring が考慮して処理しなければならないシナリオが複雑であるため、コードはより複雑になりますが、一般的な考え方は同じです。 。

// AbstractBeanFactory#getBean
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

重要な點は、循環(huán)依存関係を処理するために以前に作成したデモです。そのコードを理解し、Spring の循環(huán)依存関係の処理を見ると、それが非常に単純であることがわかります。

要約:

循環(huán)依存関係とは、2 つの Bean 間に相互參照関係があることを意味します。たとえば、A は B に依存し、B は A に依存します。ただし、Spring はプロパティの循環(huán)依存関係のみを解決でき、コンストラクターの循環(huán)依存関係は解決できません。 . このシナリオは解決できません。

Spring の循環(huán)依存関係に対するソリューションの鍵は、Bean の屬性依存関係を処理するときに、まず Bean を第 3 レベルのキャッシュに保存することです。循環(huán)依存関係がある場合は、関連する Bean を第 3 レベルのキャッシュから取得します。一次キャッシュから削除され、二次キャッシュに格納され、初期化後に最終的に一次キャッシュに格納されます。

関連する推奨事項: Java 入門チュートリアル

以上がJava のインタビューの質(zhì)問: 循環(huán)依存関係とは何か知っていますか? Spring は循環(huán)依存関係をどのように解決するのでしょうか?の詳細內(nèi)容です。詳細については、PHP 中國語 Web サイトの他の関連記事を參照してください。

このウェブサイトの聲明
この記事の內(nèi)容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰屬します。このサイトは、それに相當する法的責(zé)任を負いません。盜作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡(luò)ください。

ホットAIツール

Undress AI Tool

Undress AI Tool

脫衣畫像を無料で

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード寫真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

寫真から衣服を削除するオンライン AI ツール。

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中國語版

SublimeText3 中國語版

中國語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統(tǒng)合開発環(huán)境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

JDBCを使用してJavaのトランザクションを処理する方法は? JDBCを使用してJavaのトランザクションを処理する方法は? Aug 02, 2025 pm 12:29 PM

JDBCトランザクションを正しく処理するには、最初に自動コミットモードをオフにし、次に複數(shù)の操作を?qū)g行し、結(jié)果に応じて最終的にコミットまたはロールバックする必要があります。 1。CONN.SETAUTOCOMMIT(FALSE)を呼び出して、トランザクションを開始します。 2。挿入や更新など、複數(shù)のSQL操作を?qū)g行します。 3。すべての操作が成功した場合はconn.commit()を呼び出し、データの一貫性を確保するために例外が発生した場合はconn.rollback()を呼び出します。同時に、リソースを使用してリソースを管理し、例外を適切に処理し、接続を密接に接続するために、接続の漏れを避けるために使用する必要があります。さらに、接続プールを使用してセーブポイントを設(shè)定して部分的なロールバックを達成し、パフォーマンスを改善するためにトランザクションを可能な限り短く保つことをお勧めします。

Javaでカレンダーを操作する方法は? Javaでカレンダーを操作する方法は? Aug 02, 2025 am 02:38 AM

Java.Timeパッケージのクラスを使用して、古い日付とカレンダーのクラスを置き換えます。 2。LocalDate、LocalDateTime、LocalTimeを通じて現(xiàn)在の日付と時刻を取得します。 3。of()メソッドを使用して特定の日付と時刻を作成します。 4.プラス/マイナスメソッドを使用して、時間を不正に増加させて短縮します。 5. ZonedDateTimeとZoneIDを使用して、タイムゾーンを処理します。 6。DateTimeFormatterを介したフォーマットおよび解析の文字列。 7.インスタントを使用して、必要に応じて古い日付型と互換性があります?,F(xiàn)代のJavaでの日付処理は、java.timeapiを使用することを優(yōu)先する必要があります。

Javaフレームワークの比較:Spring Boot vs Quarkus vs Micronaut Javaフレームワークの比較:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

Pre-formanceTartuptimeMemoryusage、quarkusandmicronautleadduetocopile-timeprocessingingandgraalvsupport、withquarkusoftentylightbetterine serverlessシナリオ。

HTTPミドルウェアロギングの例を例に進めます HTTPミドルウェアロギングの例を例に進めます Aug 03, 2025 am 11:35 AM

GOのHTTPログミドルウェアは、リクエストメソッド、パス、クライアントIP、および時間がかかることを記録できます。 1. http.handlerfuncを使用してプロセッサをラップします。2。next.servehttpを呼び出す前後の開始時間と終了時間を記録します。完全なサンプルコードの実行が検証されており、中小のプロジェクトの開始に適しています。拡張機能の提案には、ステータスコードのキャプチャ、JSONログのサポート、リクエストIDトラッキングが含まれます。

Garbage CollectionはJavaでどのように機能しますか? Garbage CollectionはJavaでどのように機能しますか? Aug 02, 2025 pm 01:55 PM

JavaのGarbage Collection(GC)は、メモリを自動的に管理するメカニズムであり、到達不可能なオブジェクトを取り戻すことでメモリ漏れのリスクを軽減します。 1.GCルートオブジェクトからのオブジェクトのアクセシビリティ(スタック変數(shù)、アクティブスレッド、靜的フィールドなど)、および到達不可能なオブジェクトはゴミとしてマークされています。 2。マーククリアリングアルゴリズムに基づいて、すべての到達可能なオブジェクトをマークし、マークのないオブジェクトをクリアします。 3.世代の収集戦略を採用する:新世代(Eden、S0、S1)は頻繁にMinorGCを?qū)g行します。高齢者のパフォーマンスは少なくなりますが、MajorGCを?qū)g行するのに時間がかかります。 Metaspaceはクラスメタデータを保存します。 4。JVMはさまざまなGCデバイスを提供します。SerialGCは小さなアプリケーションに適しています。 ParallelGCはスループットを改善します。 CMSが減少します

ユーザーデータにHTML「入力」タイプを使用します ユーザーデータにHTML「入力」タイプを使用します Aug 03, 2025 am 11:07 AM

適切なHTMLinputタイプを選択すると、データの精度を向上させ、ユーザーエクスペリエンスを向上させ、使いやすさを向上させることができます。 1.テキスト、電子メール、電話、番號、日付など、データ型に従って対応する入力タイプを選択します。 2。HTML5を使用して、より直感的な相互作用方法を提供できるURL、色、範囲、検索などの新しいタイプを追加します。 3.プレースホルダーと必要な屬性を使用して、フォームフィリングの効率と精度を改善しますが、プレースホルダーがラベルを置き換えることはできないことに注意してください。

Javaビルドツールの比較:Maven vs. Gradle Javaビルドツールの比較:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

gradleisthebetterchoiceformostnewprojectoitssuperorfficability、performance、andmoderntoolingsupport.1.gradle’sgroovy/kotlindslismoreconciseandexpressiveethanmaven’sverboseml.2.gradleorformsmavenbenbumebutedwitedwitedwitedspedexは

説明された延期聲明の例で進みます 説明された延期聲明の例で進みます Aug 02, 2025 am 06:26 AM

Deferは、クリーニングリソースなど、関數(shù)が戻る前に指定された操作を?qū)g行するために使用されます。パラメーターは、延期時にすぐに評価され、関數(shù)は最後のファーストアウト(LIFO)の順に実行されます。 1.複數(shù)の債務(wù)は、宣言の逆の順序で実行されます。 2.ファイルの閉鎖などの安全なクリーニングに一般的に使用されます。 3。指定された返品値を変更できます。 4.回復(fù)に適したパニックが発生した場合でも実行されます。 5。リソースの漏れを防ぐために、ループで延期の亂用を避けます。正しい使用により、コードのセキュリティと読みやすさが向上します。

See all articles