জেএসএফ কেন গ্রাহকদের একাধিকবার কল করে


256

যাক আমি এইরূপ একটি আউটপুটেক্সট উপাদান নির্দিষ্ট করি:

<h:outputText value="#{ManagedBean.someProperty}"/>

যদি আমি কোনও লগ বার্তা মুদ্রণ করি এবং যখন গ্রাহককে কল করা somePropertyহয় এবং পৃষ্ঠাটি লোড করা হয়, তবে এটি লক্ষ্য করা তুচ্ছ যে লক্ষ্য করা যায় যে অনুরোধককে অনুরোধের জন্য একাধিকবার ডাকা হচ্ছে (আমার ক্ষেত্রে যা ঘটেছিল তা দু'বার বা তিনবার):

DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property
DEBUG 2010-01-18 23:31:40,104 (ManagedBean.java:13) - Getting some property

মানটি somePropertyগণনা করা ব্যয়বহুল হলে এটি সম্ভাব্য সমস্যা হতে পারে।

আমি কিছুটা গুগল করেছিলাম এবং এটি উপলব্ধি করা বিষয় a একটি কাজের সমাধান ছিল একটি চেক অন্তর্ভুক্ত করা এবং এটি ইতিমধ্যে গণনা করা হয়েছে কিনা তা দেখার জন্য:

private String someProperty;

public String getSomeProperty() {
    if (this.someProperty == null) {
        this.someProperty = this.calculatePropertyValue();
    }
    return this.someProperty;
}

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

এই পদ্ধতির বিকল্পগুলি কী কী? এত অপ্রয়োজনীয় কোড ছাড়া এটি অর্জনের কোনও উপায় আছে কি? জেএসএফকে এভাবে আচরণ করা থেকে বিরত করার কোনও উপায় আছে কি?

আপনার ইনপুট জন্য ধন্যবাদ!

উত্তর:


340

এটি পিছিয়ে যাওয়া এক্সপ্রেশনগুলির প্রকৃতির কারণে ঘটে #{}(নোট করুন যে "লিগ্যাসি" স্ট্যান্ডার্ড এক্সপ্রেশনগুলি ${}ঠিক তখন একই রকম আচরণ করে যখন জেএসপির পরিবর্তে ফেসলেটস ব্যবহার করা হয়)। বিলম্বিত অভিব্যক্তিটি তাত্ক্ষণিকভাবে মূল্যায়ন করা হয় না , তবে একটি ValueExpressionবস্তু হিসাবে তৈরি করা হয় এবং কোডটি কল করার সময় অভিব্যক্তির পিছনে প্রাপ্ত পদ্ধতিটি কার্যকর করা হয় ValueExpression#getValue()

উপাদানটি কোনও ইনপুট বা আউটপুট উপাদান কিনা তা নির্ভর করে (সাধারণত এটি এখানে শিখুন ) উপর নির্ভর করে এটি জেএসএফ অনুরোধ-প্রতিক্রিয়া চক্র প্রতি সাধারণত এক বা দুইবার ডাকা হবে । যাইহোক, জেএসএফ উপাদানগুলি পুনরাবৃত্ত করতে (যেমন <h:dataTable>এবং <ui:repeat>), বা এখানে এবং সেখানে renderedঅ্যাট্রিবিউটের মতো বুলিয়ান এক্সপ্রেশনে ব্যবহার করার সময় এই গণনাটি (অনেক বেশি) উপরে উঠতে পারে । জেএসএফ (বিশেষত, এল) ইএল এক্সপ্রেশনটির মূল্যায়িত ফলাফলটিকে মোটেও ক্যাশে করবে না কারণ এটি প্রতিটি কলটিতে বিভিন্ন মান ফেরত দিতে পারে (উদাহরণস্বরূপ, যখন এটি বর্তমানে পুনরাবৃত্ত ডেটেবল সারিটির উপর নির্ভরশীল)।

একটি ইএল এক্সপ্রেশন মূল্যায়ন এবং একটি গেটর পদ্ধতির অনুরোধ করা খুব সস্তার অপারেশন, সুতরাং আপনার সাধারণত এ সম্পর্কে মোটেই উদ্বিগ্ন হওয়া উচিত নয়। যাইহোক, আপনি কোনও কারণে গেটর পদ্ধতিতে ব্যয়বহুল ডিবি / ব্যবসায়িক যুক্তি সম্পাদন করার সময় গল্পটি পরিবর্তন হয়। এটি প্রতিবারই কার্যকর করা হবে!

JSF ব্যাকিং মটরশুটি মধ্যে গেটার পদ্ধতি যে ভাবে যে, তারা একমাত্র পরিকল্পিত হবে আসতে ঠিক অনুযায়ী, ইতিমধ্যে প্রস্তুতকৃত এক সম্পত্তি এবং বেশিও Javabeans স্পেসিফিকেশন । তাদের মোটেই কোনও ব্যয়বহুল ডিবি / ব্যবসায়িক যুক্তি করা উচিত নয়। তার জন্য শিম @PostConstructএবং / অথবা (ক্রিয়া) শ্রোতার পদ্ধতিগুলি ব্যবহার করা উচিত। তারা অনুরোধ ভিত্তিক জেএসএফ লাইফসাইকের কোনও সময়ে কেবল একবার মৃত্যুদন্ড কার্যকর করা হয় এবং আপনি যা চান ঠিক তেমনই।

কোনও সম্পত্তি পূর্বনির্ধারণ / লোড করার জন্য সমস্ত বিভিন্ন সঠিক উপায়ের সংক্ষিপ্তসার এখানে ।

public class Bean {

    private SomeObject someProperty;

    @PostConstruct
    public void init() {
        // In @PostConstruct (will be invoked immediately after construction and dependency/property injection).
        someProperty = loadSomeProperty();
    }

    public void onload() {
        // Or in GET action method (e.g. <f:viewAction action>).
        someProperty = loadSomeProperty();
    }           

    public void preRender(ComponentSystemEvent event) {
        // Or in some SystemEvent method (e.g. <f:event type="preRenderView">).
        someProperty = loadSomeProperty();
    }           

    public void change(ValueChangeEvent event) {
        // Or in some FacesEvent method (e.g. <h:inputXxx valueChangeListener>).
        someProperty = loadSomeProperty();
    }

    public void ajaxListener(AjaxBehaviorEvent event) {
        // Or in some BehaviorEvent method (e.g. <f:ajax listener>).
        someProperty = loadSomeProperty();
    }

    public void actionListener(ActionEvent event) {
        // Or in some ActionEvent method (e.g. <h:commandXxx actionListener>).
        someProperty = loadSomeProperty();
    }

    public String submit() {
        // Or in POST action method (e.g. <h:commandXxx action>).
        someProperty = loadSomeProperty();
        return "outcome";
    }

    public SomeObject getSomeProperty() {
        // Just keep getter untouched. It isn't intented to do business logic!
        return someProperty;
    }

}

মনে রাখবেন যে কাজের জন্য শিমের কনস্ট্রাক্টর বা ইনিশিয়ালাইজেশন ব্লক ব্যবহার করা উচিত নয় কারণ আপনি যদি সিম ম্যানেজমেন্ট ফ্রেমওয়ার্ক ব্যবহার করেন যা সিডিআইয়ের মতো প্রক্সি ব্যবহার করে তবে এটি একাধিকবার আহ্বান করা হতে পারে।

কিছু সীমাবদ্ধ ডিজাইনের প্রয়োজনীয়তার কারণে যদি আপনার পক্ষে সত্যিই অন্য কোনও উপায় না থাকে, তবে আপনাকে গেটর পদ্ধতির ভিতরে অলস লোডিংয়ের প্রবর্তন করা উচিত। অর্থ্যাৎ সম্পত্তিটি যদি থাকে তবে এটি nullলোড করে সম্পত্তিটিতে অর্পণ করুন, অন্যথায় এটি ফিরিয়ে দিন।

    public SomeObject getSomeProperty() {
        // If there are really no other ways, introduce lazy loading.
        if (someProperty == null) {
            someProperty = loadSomeProperty();
        }

        return someProperty;
    }

এইভাবে ব্যয়বহুল ডিবি / ব্যবসায়িক যুক্তি অকারণে প্রতিটি একক গেট কলটিতে কার্যকর করা হবে না।

আরো দেখুন:


5
ব্যবসার যুক্তি করতে কেবল গেটর ব্যবহার করবেন না। এখানেই শেষ. আপনার কোড যুক্তি পুনরায় সাজান। আমার বাজি যে এটি ইতিমধ্যে কেবলমাত্র নির্মাণকারী, পোস্টকন্সট্রাক্ট বা অ্যাকশন পদ্ধতিটি স্মার্ট উপায়ে ব্যবহার করে ঠিক করা হয়েছে।
BalusC

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

3
আপনি যেমন পরিষ্কারভাবে বলেছেন সে হিসাবে তারা ডেটা ফিরিয়ে দেওয়ার চেয়ে আরও বেশি কিছু করবে কিনা আশা করুন :)
বালুস সি


2
@ হ্যারি: এটি আচরণ পরিবর্তন করবে না। আপনি যাইহোক শর্তসাপেক্ষে অলস লোডিং এবং / অথবা দ্বারা বর্তমান ফেজ আইডি পরীক্ষা করে কোনও ব্যবসায়ের যুক্তি পরিচালনা করতে পারেন FacesContext#getCurrentPhaseId()
বালাসসি

17

জেএসএফ 2.0 দিয়ে আপনি কোনও সিস্টেমের ইভেন্টে শ্রোতাকে সংযুক্ত করতে পারেন

<h:outputText value="#{ManagedBean.someProperty}">
   <f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />
</h:outputText>

বিকল্পভাবে আপনি জেএসএফ পৃষ্ঠাটি একটি f:viewট্যাগে বন্ধ করতে পারেন

<f:view>
   <f:event type="preRenderView" listener="#{ManagedBean.loadSomeProperty}" />

      .. jsf page here...

<f:view>

9

আমি কীভাবে স্প্রিং এওপি দিয়ে জেএসএফ মটরশুটি সংগ্রহকারীকে ক্যাশে করব সে সম্পর্কে একটি নিবন্ধ লিখেছি ।

আমি একটি সাধারণ তৈরি করি MethodInterceptorযা একটি বিশেষ টীকা সহ সমস্ত টীকাকে টীকাযুক্ত করে:

public class CacheAdvice implements MethodInterceptor {

private static Logger logger = LoggerFactory.getLogger(CacheAdvice.class);

@Autowired
private CacheService cacheService;

@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {

    String key = methodInvocation.getThis() + methodInvocation.getMethod().getName();

    String thread = Thread.currentThread().getName();

    Object cachedValue = cacheService.getData(thread , key);

    if (cachedValue == null){
        cachedValue = methodInvocation.proceed();
        cacheService.cacheData(thread , key , cachedValue);
        logger.debug("Cache miss " + thread + " " + key);
    }
    else{
        logger.debug("Cached hit " + thread + " " + key);
    }
    return cachedValue;
}


public CacheService getCacheService() {
    return cacheService;
}
public void setCacheService(CacheService cacheService) {
    this.cacheService = cacheService;
}

}

এই ইন্টারসেপ্টারটি একটি বসন্ত কনফিগারেশন ফাইলে ব্যবহৃত হয়:

    <bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="pointcut">
        <bean class="org.springframework.aop.support.annotation.AnnotationMatchingPointcut">
            <constructor-arg index="0"  name="classAnnotationType" type="java.lang.Class">
                <null/>
            </constructor-arg>
            <constructor-arg index="1" value="com._4dconcept.docAdvance.jsfCache.annotation.Cacheable" name="methodAnnotationType" type="java.lang.Class"/>
        </bean>
    </property>
    <property name="advice">
        <bean class="com._4dconcept.docAdvance.jsfCache.CacheAdvice"/>
    </property>
</bean>

আশা করি এটি সাহায্য করবে!


6

মূলত প্রাইমফ্রিজ ফোরামে পোস্ট হয়েছে @ http://forum.primefaces.org/viewtopic.php?f=3&t=29546

সম্প্রতি, আমি আমার অ্যাপ্লিকেশনটির পারফরম্যান্স মূল্যায়ন, জেপিএ কোয়েরিগুলি টিউন করা, গতিশীল এসকিউএল কোয়েরিগুলিকে নামযুক্ত প্রশ্নের সাথে প্রতিস্থাপন করেছি এবং ঠিক আজ সকালে, আমি স্বীকার করেছি যে জাটার ভিজ্যুয়াল ভিএম-তে একটি গেটর পদ্ধতি হট স্পটের চেয়ে বেশি ছিল আমার কোড (বা আমার কোডের সিংহভাগ)

গেটর পদ্ধতি:

PageNavigationController.getGmapsAutoComplete()

Ui দ্বারা রেফারেন্স করা: index.xhtml এ অন্তর্ভুক্ত

নীচে, আপনি দেখতে পাবেন যে পেজ নেভিগেশনকন্ট্রোলআরজিটম্যাপস অটো কমপ্লিট () জাভা ভিজ্যুয়াল ভিএম-তে একটি হট স্পট (পারফরম্যান্স ইস্যু)। আপনি যদি আরও নীচে তাকান, স্ক্রিন ক্যাপচারে, আপনি দেখতে পাবেন যে getLazyModel (), প্রাইমফ্রিজস অলস ডেটেটেবল গেটর পদ্ধতিটিও একটি হট স্পট, কেবল তখনই যখন এন্ডুয়েসার প্রচুর পরিমাণে 'অলস ডেটাটেবল' স্টাফ / ক্রিয়াকলাপ / কার্যগুলি করে থাকে অ্যাপে। :)

জাভা ভিজ্যুয়াল ভিএম: হট স্পট দেখাচ্ছে

নীচে (মূল) কোডটি দেখুন।

public Boolean getGmapsAutoComplete() {
    switch (page) {
        case "/orders/pf_Add.xhtml":
        case "/orders/pf_Edit.xhtml":
        case "/orders/pf_EditDriverVehicles.xhtml":
            gmapsAutoComplete = true;
            break;
        default:
            gmapsAutoComplete = false;
            break;
    }
    return gmapsAutoComplete;
}

Index.xhtml এ নিম্নলিখিত দ্বারা রেফারেন্স করা:

<h:head>
    <ui:include src="#{pageNavigationController.gmapsAutoComplete ? '/head_gmapsAutoComplete.xhtml' : (pageNavigationController.gmaps ? '/head_gmaps.xhtml' : '/head_default.xhtml')}"/>
</h:head>

সমাধান: যেহেতু এটি একটি 'গেটর' পদ্ধতি, তাই কোডটি সরানোর কোডটি বলা হবে এবং পদ্ধতিটি বলার আগে জিপাস অটো কমপ্লিটকে মান নির্ধারণ করুন; নীচে কোড দেখুন।

/*
 * 2013-04-06 moved switch {...} to updateGmapsAutoComplete()
 *            because performance = 115ms (hot spot) while
 *            navigating through web app
 */
public Boolean getGmapsAutoComplete() {
    return gmapsAutoComplete;
}

/*
 * ALWAYS call this method after "page = ..."
 */
private void updateGmapsAutoComplete() {
    switch (page) {
        case "/orders/pf_Add.xhtml":
        case "/orders/pf_Edit.xhtml":
        case "/orders/pf_EditDriverVehicles.xhtml":
            gmapsAutoComplete = true;
            break;
        default:
            gmapsAutoComplete = false;
            break;
    }
}

পরীক্ষার ফলাফল: পেজ নেভিগেশনকন্ট্রোলআরজিটম্যাপস অটো কমপ্লিট () আর জাভা ভিজ্যুয়াল ভিএম-তে কোনও হট স্পট নয় (এমনকি আরও দেখাবে না)

এই বিষয়টি ভাগ করে নেওয়া, যেহেতু বিশেষজ্ঞ ব্যবহারকারীদের মধ্যে অনেকে জুনিয়র জেএসএফ বিকাশকারীকে 'গেটর' পদ্ধতিতে কোড যুক্ত না করার পরামর্শ দিয়েছেন। :)


4

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


3

আপনি সম্ভবত কিছু ধরণের पहलू তৈরি করতে এওপি ব্যবহার করতে পারেন যা আমাদের প্রাপ্তদের ফলাফলকে একটি কনফিগারযোগ্য পরিমাণের জন্য ক্যাশে করে। এটি আপনাকে কয়েক ডজন অ্যাক্সেসরগুলিতে কপিরাইট-পেস্ট করে বয়লারপ্লেট কোড থেকে আটকাবে।


আপনি কি কথা বলছেন এই বসন্তের এওপি? আপনি কি জানবেন আমি কোথাও কোনও কোড স্নিপেট বা দু'টো দিক নিয়ে কাজ করতে পারি? স্প্রিং ডকুমেন্টেশনের পুরো 6th ষ্ঠ অধ্যায়টি পড়া ওভারকিলের মতো মনে হচ্ছে যেহেতু আমি স্প্রিং ব্যবহার করছি না;)
সেবাস

-1

যদি কিছু প্রপার্টিটির মান গণনা করা ব্যয়বহুল হয় তবে এটি সম্ভবত সমস্যা হতে পারে।

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


সুতরাং প্রশ্ন - যদি কিছুপ্রোপার্টি গণনা করার জন্য ব্যয়বহুল কিছুটির সাথে মিলে যায় (বা আপনি এটি কোনও ডাটাবেস অ্যাক্সেস বা ফ্যাক্টরিং প্রাইমগুলিতে অ্যাক্সেস রেখেছিলেন) তবে অনুরোধ অনুযায়ী বেশ কয়েকবার গণনা করা এড়ানোর সর্বোত্তম উপায় কী এবং আমি যে প্রশ্নটিতে তালিকাভুক্ত করেছি সেই সমাধানটি কি? সেরা এক। আপনি যদি প্রশ্নের উত্তর দিচ্ছেন না, মন্তব্যগুলি পোস্ট করার জন্য ভাল জায়গা, না? এছাড়াও, আপনার পোস্টটি বালাসকের পোস্টে আপনার মন্তব্যের সাথে বিরোধিতা করে বলে মনে হচ্ছে - যে মন্তব্যে আপনি বলেছিলেন যে উড়তে গণনা করা ভাল, এবং আপনার পোস্টে আপনি বলেছিলেন যে এটি বোকামি। আমি জিজ্ঞাসা করতে পারি আপনি লাইনটি কোথায় আঁকেন?
Sevas

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

-1

আমি স্টক জেএসএফের পরিবর্তে প্রাইমফেস হিসাবে এই জাতীয় ফ্রেমওয়ার্ক ব্যবহার করার পরামর্শ দেব, তারা জেএসএফ টিমের আগে এ জাতীয় সমস্যাগুলি সমাধান করে। প্রাইমফেসগুলিতে g আপনি আংশিক জমা দিতে পারবেন। অন্যথায় বালুসসি এটি ভালভাবে ব্যাখ্যা করেছে।


-2

এটি এখনও জেএসএফের বড় সমস্যা। উদাহরণস্বরূপ উদাহরণস্বরূপ যদি আপনার isPermittedToBlaBlaসুরক্ষা চেকগুলির জন্য কোনও পদ্ধতি থাকে এবং আপনার দৃষ্টিতে আপনার কাছে থাকে rendered="#{bean.isPermittedToBlaBla}তবে সেই পদ্ধতিটি একাধিকবার বলা হবে।

সুরক্ষা চেক জটিল হতে পারে যেমন। এলডিএপি কোয়েরি ইত্যাদি তাই আপনাকে অবশ্যই এড়াতে হবে

Boolean isAllowed = null ... if(isAllowed==null){...} return isAllowed?

এবং আপনাকে অবশ্যই অনুরোধ অনুযায়ী একটি সেশন বিনের মধ্যে অবশ্যই তা নিশ্চিত করতে হবে।

ইচ্ছ ভাবছেন একাধিক কল এড়াতে জেএসএফকে এখানে কিছু এক্সটেনশন প্রয়োগ করতে হবে (উদাহরণস্বরূপ ধাপের @Phase(RENDER_RESPONSE)পরে একবারে এই পদ্ধতিটি কল করুন RENDER_RESPONSE...)


2
আপনি অনুরোধপ্যারামিটারম্যাপ
ক্রিস্টোফ রাউসি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.