স্প্রিং ক্যাশে @ ক্যাশেযোগ্য - একই শিমের অন্য কোনও পদ্ধতি থেকে কল করার সময় কাজ করছেন না


107

একই শিমের অন্য কোনও পদ্ধতি থেকে ক্যাশেড পদ্ধতিতে কল করার সময় স্প্রিং ক্যাশে কাজ করছে না।

আমার সমস্যাটি পরিষ্কার উপায়ে ব্যাখ্যা করার জন্য এখানে একটি উদাহরণ রয়েছে।

কনফিগারেশন:

<cache:annotation-driven cache-manager="myCacheManager" />

<bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
    <property name="cacheManager" ref="myCache" />
</bean>

<!-- Ehcache library setup -->
<bean id="myCache"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:shared="true">
    <property name="configLocation" value="classpath:ehcache.xml"></property>
</bean>

<cache name="employeeData" maxElementsInMemory="100"/>  

ক্যাশেড পরিষেবা:

@Named("aService")
public class AService {

    @Cacheable("employeeData")
    public List<EmployeeData> getEmployeeData(Date date){
    ..println("Cache is not being used");
    ...
    }

    public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
        List<EmployeeData> employeeData = getEmployeeData(date);
        ...
    }

}

ফলাফল :

aService.getEmployeeData(someDate);
output: Cache is not being used
aService.getEmployeeData(someDate); 
output: 
aService.getEmployeeEnrichedData(someDate); 
output: Cache is not being used

getEmployeeDataপদ্ধতি কল ব্যবহারের ক্যাশে employeeDataদ্বিতীয় কলে আশানুরূপ। ক্লাসের getEmployeeDataমধ্যে যখন পদ্ধতিটি কল করা হয় AService(ইন getEmployeeEnrichedData), তখন ক্যাশে ব্যবহৃত হচ্ছে না।

এইভাবে কী বসন্তের ক্যাশে কাজ করে বা আমি কিছু মিস করছি?


আপনি কি someDateপরমের জন্য একই মান ব্যবহার করছেন ?
দেউফিউ

@ ডেভিফাই হ্যাঁ, এটি একই
বালা

উত্তর:


158

আমি বিশ্বাস করি এটি কীভাবে কাজ করে। আমি যা পড়তে মনে করি সেখান থেকে একটি প্রক্সি শ্রেণি উত্পন্ন হয় যা সমস্ত অনুরোধকে বাধা দেয় এবং ক্যাশেড মানটির সাথে সাড়া দেয় তবে একই শ্রেণীর মধ্যে 'অভ্যন্তরীণ' কলগুলি ক্যাশেড মান পাবে না।

Https://code.google.com/p/ehcache-spring-annotations/wiki/UsingCacheable থেকে

প্রক্সি দিয়ে আসা কেবলমাত্র বাহ্যিক পদ্ধতি কলগুলিই বাধা দেওয়া হয়েছে। এর অর্থ হ'ল স্ব-আহ্বান, ফলস্বরূপ, টার্গেট অবজেক্টের মধ্যে থাকা কোনও পদ্ধতিকে লক্ষ্য অবজেক্টের অন্য পদ্ধতিটি কল করে, রানটাইমে যখন অনুরোধ করা পদ্ধতিটি @ ক্যাশেবল দ্বারা চিহ্নিত করা হয় তখনও প্রকৃত ক্যাশে বাধা দিতে পারে না।


1
ঠিক আছে, আপনি যদি দ্বিতীয় কলটিকেও ক্যাশেযোগ্য করতে পারেন তবে এটির জন্য কেবল একটি ক্যাশে মিস থাকবে। এটি হ'ল এমপ্লয়ই এনারিক্সডেটা পাওয়ার প্রথম কলটি ক্যাশে বাইপাস করবে। এটির দ্বিতীয় কলটি প্রথম কল থেকে এমপ্লোয়েইনরিশেডডেটা থেকে আগের ক্যাশেড রিটার্ন ব্যবহার করবে।
শন ডি

1
@ বালা আমার একই সমস্যা রয়েছে, আমার সমাধানটি @Cacheableডিএও-তে চলেছে :( আপনার আরও ভাল সমাধান থাকলে দয়া করে আমাকে জানান, ধন্যবাদ।
ভাদাইহাইপ

2
আপনি একটি পরিষেবা যেমন ক্যাশে সার্ভিস লিখতে পারেন এবং পরিষেবাগুলিতে আপনার সমস্ত ক্যাশে পদ্ধতিতে রেখে দিতে পারেন। আপনার যেখানে পরিষেবা প্রয়োজন সেটির স্বীকৃতি দিন এবং পদ্ধতিগুলি কল করুন। আমার ক্ষেত্রে সাহায্য করেছে।
DOUBL3P

স্প্রিং 4.3 যেহেতু এই ব্যবহার সমাধান করা যেতে পারে @Resourceস্ব-autowiring দেখুন উদাহরণ stackoverflow.com/a/48867068/907576
radistao

1
এছাড়াও বাহ্যিক @Cacheableপদ্ধতিটি হওয়া উচিত public, এটি প্যাকেজ-ব্যক্তিগত পদ্ধতিতে কাজ করে না। এটি হার্ড উপায় খুঁজে পেয়েছি।
আনন্দ

36

স্প্রিং ৪.৩ -এর ফলে @Resourceটীকা দেওয়ার চেয়ে স্ব-স্বায়ত্ব ব্যবহার করে সমস্যার সমাধান করা যেতে পারে :

@Component
@CacheConfig(cacheNames = "SphereClientFactoryCache")
public class CacheableSphereClientFactoryImpl implements SphereClientFactory {

    /**
     * 1. Self-autowired reference to proxified bean of this class.
     */
    @Resource
    private SphereClientFactory self;

    @Override
    @Cacheable(sync = true)
    public SphereClient createSphereClient(@Nonnull TenantConfig tenantConfig) {
        // 2. call cached method using self-bean
        return self.createSphereClient(tenantConfig.getSphereClientConfig());
    }

    @Override
    @Cacheable(sync = true)
    public SphereClient createSphereClient(@Nonnull SphereClientConfig clientConfig) {
        return CtpClientConfigurationUtils.createSphereClient(clientConfig);
    }
}

2
4.3.17এটি এর অধীনে চেষ্টা করা হয়েছে এবং এটি কার্যকর হয়নি, selfপ্রক্সি দিয়ে যাওয়ার জন্য কলগুলি করা হয়নি এবং ক্যাশে (এখনও) বাইপাস করা হয়েছে।
ম্যাডব্রেকস

আমার জন্য কাজ করেছেন। ক্যাশে হিট। আমি এই তারিখ হিসাবে সর্বশেষ বসন্ত নির্ভরতা ব্যবহার।
টমাস বিসিয়াক

আমি কি কেবলমাত্র এই ভাবনাগুলিকেই ভাঙ্গা ভাবি, সিঙ্গলটন মিক্স ইত্যাদির মতো দেখি?
2mia

আমি স্প্রিং বুট স্টার্টার সংস্করণ ব্যবহার করেছি - ২.১.০. রিলিজ, এবং আমারও একই সমস্যা ছিল। এই নির্দিষ্ট সমাধানটি কবজির মতো কাজ করেছিল।
দীপন প্রভু বাবু

18

নীচের উদাহরণটি হ'ল আমি একই শিমের মধ্য থেকে প্রক্সিটি হিট করতে ব্যবহার করি এটি @ মারিও-ইআইস সমাধানের অনুরূপ, তবে আমি এটি কিছুটা বেশি পঠনযোগ্য দেখতে পেয়েছি (সম্ভবত এটি :-) নয়। যাইহোক, আমি @ ক্যাশেবল টিকাগুলি পরিষেবা স্তরে রাখতে চাই:

@Service
@Transactional(readOnly=true)
public class SettingServiceImpl implements SettingService {

@Inject
private SettingRepository settingRepository;

@Inject
private ApplicationContext applicationContext;

@Override
@Cacheable("settingsCache")
public String findValue(String name) {
    Setting setting = settingRepository.findOne(name);
    if(setting == null){
        return null;
    }
    return setting.getValue();
}

@Override
public Boolean findBoolean(String name) {
    String value = getSpringProxy().findValue(name);
    if (value == null) {
        return null;
    }
    return Boolean.valueOf(value);
}

/**
 * Use proxy to hit cache 
 */
private SettingService getSpringProxy() {
    return applicationContext.getBean(SettingService.class);
}
...

বসন্ত শিমের মধ্যে নতুন লেনদেন শুরু করা দেখুন


1
অ্যাপ্লিকেশন প্রসঙ্গে অ্যাক্সেস করা, যেমন applicationContext.getBean(SettingService.class);নির্ভরতা ইনজেকশনের বিপরীত। আমি সেই স্টাইলটি এড়িয়ে চলার পরামর্শ দিই।
সিঙ্গলশট

2
হ্যাঁ এটি এড়ানো ভাল হবে তবে আমি এই সমস্যার আরও ভাল সমাধান দেখতে পাচ্ছি না।
molholm

10

ক্ষুদ্র প্রকল্পগুলির জন্য আমি একই ক্লাসের মধ্যে কেবলমাত্র পদ্ধতির কলের প্রান্তিক ব্যবহার সহ যা করি তা এখানে। ইন-কোড ডকুমেন্টেশনটিকে দৃ strongly়ভাবে পরামর্শ দেওয়া হয়েছে, কারণ এটি সহকর্মীদের কাছে স্ট্রাইজ দেখাচ্ছে। তবে এটি পরীক্ষা করা সহজ, সহজ, দ্রুত অর্জন এবং আমাকে সম্পূর্ণ প্রস্ফুটিত AspectJ উপকরণ বাদ দেয়। তবে বেশি ভারী ব্যবহারের জন্য আমি অ্যাসপেক্টজে সমাধানের পরামর্শ দিই।

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class AService {

    private final AService _aService;

    @Autowired
    public AService(AService aService) {
        _aService = aService;
    }

    @Cacheable("employeeData")
    public List<EmployeeData> getEmployeeData(Date date){
        ..println("Cache is not being used");
        ...
    }

    public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
        List<EmployeeData> employeeData = _aService.getEmployeeData(date);
        ...
    }
}

1
আপনি AspectJ দিয়ে একটি উদাহরণ দিতে পারেন?
সেরজিও বিলেলো

এই উত্তরটি stackoverflow.com/a/34090850/1371329 এর সদৃশ ।
jaco0646

3

আমার ক্ষেত্রে আমি পরিবর্তনশীল যুক্ত:

@Autowired
private AService  aService;

সুতরাং আমি getEmployeeDataব্যবহার করে পদ্ধতিটি কলaService

@Named("aService")
public class AService {

@Cacheable("employeeData")
public List<EmployeeData> getEmployeeData(Date date){
..println("Cache is not being used");
...
}

public List<EmployeeEnrichedData> getEmployeeEnrichedData(Date date){
    List<EmployeeData> employeeData = aService.getEmployeeData(date);
    ...
}

}

এটি এক্ষেত্রে ক্যাশে ব্যবহার করবে।


2

আপনার শিমের চারপাশে প্রক্সি তৈরি করতে স্ট্যাটিক বয়ন ব্যবহার করুন। এই ক্ষেত্রে এমনকি 'অভ্যন্তরীণ' পদ্ধতিগুলি সঠিকভাবে কাজ করবে


"স্ট্যাটিক বয়ন" কী? গুগল খুব একটা সাহায্য করে না। এই ধারণাটি বুঝতে কোন পয়েন্টার?
বালা

@ বালা - কেবলমাত্র আমাদের প্রকল্পে উদাহরণস্বরূপ আমরা <iajcসংকলক ব্যবহার করি (পিঁপড়ে থেকে) যা ক্যাশে-সক্ষম শ্রেণীর জন্য সমস্ত প্রয়োজনীয় দিকগুলি সমাধান করে।
শোধ করুন

0

আমি FactoryInternalCacheএই উদ্দেশ্যে প্রকৃত ক্যাশে সহ অভ্যন্তরীণ অভ্যন্তরীণ বিন ( ) ব্যবহার করি :

@Component
public class CacheableClientFactoryImpl implements ClientFactory {

private final FactoryInternalCache factoryInternalCache;

@Autowired
public CacheableClientFactoryImpl(@Nonnull FactoryInternalCache factoryInternalCache) {
    this.factoryInternalCache = factoryInternalCache;
}

/**
 * Returns cached client instance from cache.
 */
@Override
public Client createClient(@Nonnull AggregatedConfig aggregateConfig) {
    return factoryInternalCache.createClient(aggregateConfig.getClientConfig());
}

/**
 * Returns cached client instance from cache.
 */
@Override
public Client createClient(@Nonnull ClientConfig clientConfig) {
    return factoryInternalCache.createClient(clientConfig);
}

/**
 * Spring caching feature works over AOP proxies, thus internal calls to cached methods don't work. That's why
 * this internal bean is created: it "proxifies" overloaded {@code #createClient(...)} methods
 * to real AOP proxified cacheable bean method {@link #createClient}.
 *
 * @see <a href="/programming/16899604/spring-cache-cacheable-not-working-while-calling-from-another-method-of-the-s">Spring Cache @Cacheable - not working while calling from another method of the same bean</a>
 * @see <a href="/programming/12115996/spring-cache-cacheable-method-ignored-when-called-from-within-the-same-class">Spring cache @Cacheable method ignored when called from within the same class</a>
 */
@EnableCaching
@CacheConfig(cacheNames = "ClientFactoryCache")
static class FactoryInternalCache {

    @Cacheable(sync = true)
    public Client createClient(@Nonnull ClientConfig clientConfig) {
        return ClientCreationUtils.createClient(clientConfig);
    }
}
}

0

এখন পর্যন্ত সবচেয়ে সহজ সমাধানটি কেবল এর মতো উল্লেখ করা:

AService.this.getEmployeeData(date);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.