வணக்கம்! இன்று நாம் ஒரு முக்கியமான மற்றும் சுவாரஸ்யமான தலைப்பைக் கருத்தில் கொள்வோம்: ஜாவாவில் டைனமிக் ப்ராக்ஸி வகுப்புகளை உருவாக்குதல். இது மிகவும் எளிமையானது அல்ல, எனவே எடுத்துக்காட்டுகளைப் பயன்படுத்தி அதைக் கண்டுபிடிக்க முயற்சிப்போம் :) எனவே, மிக முக்கியமான கேள்வி: டைனமிக் ப்ராக்ஸிகள் என்றால் என்ன, அவை எதற்காக? ப்ராக்ஸி வகுப்பு என்பது அசல் வகுப்பின் மேல் உள்ள ஒரு வகையான "ஆட்-ஆன்" ஆகும், இது தேவைப்பட்டால் அசல் வகுப்பின் நடத்தையை மாற்ற அனுமதிக்கிறது. "நடத்தையை மாற்றுவது" என்றால் என்ன, அது எப்படி வேலை செய்கிறது? ஒரு எளிய உதாரணத்தைக் கவனியுங்கள். எங்களிடம் ஒரு நபர் இடைமுகம் மற்றும் இந்த இடைமுகத்தை செயல்படுத்தும் எளிய மேன் வகுப்பு உள்ளது என்று வைத்துக்கொள்வோம்
இந்த நிலையில் நாம் என்ன செய்ய வேண்டும்? எங்களுக்கு சில விஷயங்கள் தேவைப்படும்:
எடுத்துக்காட்டாக, பாதுகாப்பு தொடர்பான பிரபலமான தொழில்நுட்பங்கள் மற்றும் கட்டமைப்புகளில் இது தீவிரமாகப் பயன்படுத்தப்படுகிறது. உங்கள் திட்டத்தில் உள்நுழைந்துள்ள பயனர்களால் மட்டுமே செயல்படுத்தப்பட வேண்டிய 20 முறைகள் உங்களிடம் உள்ளன என்று கற்பனை செய்து பாருங்கள். நீங்கள் கற்றுக்கொண்ட நுட்பங்களைப் பயன்படுத்தி, ஒவ்வொரு முறையிலும் சரிபார்ப்புக் குறியீட்டை நகலெடுக்காமல் பயனர் சரியான நற்சான்றிதழ்களை உள்ளிட்டுள்ளாரா என்பதைப் பார்க்க, இந்த 20 முறைகளில் எளிதாகச் சேர்க்கலாம். அல்லது அனைத்து பயனர் செயல்களும் பதிவு செய்யப்படும் ஒரு பதிவை நீங்கள் உருவாக்க விரும்புகிறீர்கள் என்று வைத்துக்கொள்வோம். ப்ராக்ஸியைப் பயன்படுத்தி இதைச் செய்வதும் எளிதானது. இப்போதும் கூட, மேலே உள்ள எங்கள் எடுத்துக்காட்டில் நீங்கள் குறியீட்டைச் சேர்க்கலாம், இதன் மூலம் நீங்கள் அழைக்கும் போது முறையின் பெயர் காட்டப்படும் () , மேலும் இது எங்கள் நிரலின் மிக எளிய பதிவை உருவாக்கும் :) முடிவில், ஒரு முக்கியமான வரம்புக்கு கவனம் செலுத்துங்கள். ப்ராக்ஸி பொருள் இடைமுகங்களுடன் வேலை செய்கிறது, வகுப்புகள் அல்ல. ஒரு இடைமுகத்திற்காக ப்ராக்ஸி உருவாக்கப்பட்டது. இந்தக் குறியீட்டைப் பாருங்கள்:
public interface Person {
public void introduce(String name);
public void sayAge(int age);
public void sayWhereFrom(String city, String country);
}
public class Man implements Person {
private String name;
private int age;
private String city;
private String country;
public Man(String name, int age, String city, String country) {
this.name = name;
this.age = age;
this.city = city;
this.country = country;
}
@Override
public void introduce(String name) {
System.out.println("My name is " + this.name);
}
@Override
public void sayAge(int age) {
System.out.println("I am " + this.age + " years old");
}
@Override
public void sayWhereFrom(String city, String country) {
System.out.println("I'm from " + this.city + ", " + this.country);
}
// ...getters, setters, etc.
}
எங்கள் மேன் வகுப்பில் 3 முறைகள் உள்ளன: அறிமுகம், சொல்லும் வயது, மற்றும் எங்கிருந்து சொல்வது. இந்த வகுப்பை ஒரு ஆஃப்-தி-ஷெல்ஃப் JAR லைப்ரரியின் ஒரு பகுதியாக நாங்கள் பெற்றுள்ளோம் என்று கற்பனை செய்து பாருங்கள், அதன் குறியீட்டை எங்களால் மாற்றி எழுத முடியாது. ஆனால் நாம் அதன் நடத்தையையும் மாற்ற வேண்டும். எடுத்துக்காட்டாக, எங்கள் பொருளில் எந்த முறையை அழைக்கலாம் என்று எங்களுக்குத் தெரியாது, ஆனால் எங்கள் நபர் "ஹாய்!" (அநாகரீகமாக இருக்கும் ஒருவரை யாரும் விரும்புவதில்லை) எந்த முறைகளையும் அழைக்கும்போது. 
-
அழைப்பிதழ் கையாளுபவர்
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonInvocationHandler implements InvocationHandler {
private Person person;
public PersonInvocationHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Hi!");
return null;
}
}
நாம் ஒரே ஒரு இடைமுக முறையை மட்டுமே செயல்படுத்த வேண்டும்: invoke() . மேலும், இது நமக்குத் தேவையானதைச் செய்கிறது: இது எங்கள் பொருளுக்கான அனைத்து முறை அழைப்புகளையும் இடைமறித்து, தேவையான நடத்தையைச் சேர்க்கிறது (இன்வொக் () முறையின் உள்ளே, கன்சோலுக்கு "ஹாய்!" என்பதை வெளியிடுகிறோம்).
- அசல் பொருள் மற்றும் அதன் பிரதிநிதிகள்.
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
// Create the original object
Man arnold = new Man("Arnold", 30, "Thal", "Austria");
// Get the class loader from the original object
ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();
// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
// Call one of our original object's methods on the proxy object
proxyArnold.introduce(arnold.getName());
}
}
இது மிகவும் எளிமையானதாகத் தெரியவில்லை! குறியீட்டின் ஒவ்வொரு வரிக்கும் ஒரு கருத்தைச் சேர்த்துள்ளேன். என்ன நடக்கிறது என்பதை இன்னும் விரிவாகப் பார்ப்போம். முதல் வரியில், நாங்கள் ப்ராக்ஸிகளை உருவாக்கும் அசல் பொருளை உருவாக்குகிறோம். பின்வரும் இரண்டு வரிகள் உங்களுக்கு சிரமத்தை ஏற்படுத்தலாம்:
// Get the class loader from the original object
ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();
// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();
உண்மையில், இங்கு உண்மையில் சிறப்பு எதுவும் நடக்கவில்லை :) நான்காவது வரியில், சிறப்பு ப்ராக்ஸி வகுப்பையும் அதன் நிலையான newProxyInstance() முறையையும் பயன்படுத்துகிறோம் :
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
இந்த முறை நமது ப்ராக்ஸி பொருளை உருவாக்குகிறது. கடைசி கட்டத்தில் (அதன் கிளாஸ்லோடர் மற்றும் அதன் இடைமுகங்களின் பட்டியல்) நாங்கள் பெற்ற அசல் வகுப்பைப் பற்றிய தகவலையும், முன்பு உருவாக்கப்பட்ட இன்வொக்கேஷன்ஹேண்ட்லர் பொருளையும் முறைக்கு அனுப்புகிறோம் . முக்கிய விஷயம் என்னவென்றால், எங்கள் அசல் அர்னால்ட் பொருளை அழைப்பிதழ் கையாளுபவருக்கு அனுப்ப மறக்காதீர்கள் , இல்லையெனில் "கையாளுவதற்கு" எதுவும் இருக்காது :) நாங்கள் என்ன செய்தோம்? இப்போது எங்களிடம் ஒரு ப்ராக்ஸி பொருள் உள்ளது: ப்ராக்ஸிஆர்னால்ட் . இது நபர் இடைமுகத்தின் எந்த முறைகளையும் அழைக்கலாம் . ஏன்? ஏனென்றால், எல்லா இடைமுகங்களின் பட்டியலை நாங்கள் இங்கே கொடுத்துள்ளோம்:
// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
இப்போது அது நபர் இடைமுகத்தின் அனைத்து முறைகளையும் பற்றி அறிந்திருக்கிறது . கூடுதலாக, அர்னால்ட் பொருளுடன் வேலை செய்ய உள்ளமைக்கப்பட்ட PersonInvocationHandler பொருளை நாங்கள் எங்கள் ப்ராக்ஸிக்கு அனுப்பினோம் :
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
இப்போது நாம் ப்ராக்ஸி பொருளில் உள்ள நபர் இடைமுகத்தின் எந்த முறையை அழைத்தாலும் , எங்கள் கையாளுபவர் அழைப்பை இடைமறித்து, அதற்குப் பதிலாக அதன் சொந்த அழைப்பு() முறையைச் செயல்படுத்துகிறார். முக்கிய() முறையை இயக்க முயற்சிப்போம் ! கன்சோல் வெளியீடு:
Hi!
சிறப்பானது! அசல் Person.introduce() முறைக்கு பதிலாக , எங்கள் PersonInvocationHandler() இன் invoke() முறை அழைக்கப்படுகிறது:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Hi!");
return null;
}
"வணக்கம்!" கன்சோலில் காட்டப்படும், ஆனால் இது நாங்கள் விரும்பிய நடத்தை சரியாக இல்லை :/ நாங்கள் அடைய முயற்சிப்பது முதலில் "ஹாய்!" பின்னர் அசல் முறையை அழைக்கவும், வேறுவிதமாகக் கூறினால், முறை அழைப்பு
proxyArnold.introduce(arnold.getName());
"ஹாய்! என் பெயர் அர்னால்ட்" என்பதைக் காட்ட வேண்டும், வெறுமனே "ஹாய்!" இதை நாம் எப்படி அடைய முடியும்? இது சிக்கலானது அல்ல: எங்கள் கையாளுபவர் மற்றும் அழைப்பிதழ் () முறைக்கு சில சுதந்திரங்களை நாம் எடுக்க வேண்டும் :) இந்த முறைக்கு என்ன வாதங்கள் அனுப்பப்படுகின்றன என்பதைக் கவனியுங்கள்:
public Object invoke(Object proxy, Method method, Object[] args)
invoke () முறையானது முதலில் செயல்படுத்தப்பட்ட முறை மற்றும் அதன் அனைத்து வாதங்களுக்கும் (Method method, Object[] args) அணுகலைக் கொண்டுள்ளது. வேறு வார்த்தைகளில் கூறுவதானால், நாம் proxyArnold.introduce(arnold.getName()) முறையை அழைத்தால் , invoke() முறை introduce() முறைக்கு பதிலாக அழைக்கப்படுகிறது , இந்த முறைக்குள் அசல் introduce() முறையை அணுகலாம். அதன் வாதமும்! இதன் விளைவாக, நாம் இதைச் செய்யலாம்:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonInvocationHandler implements InvocationHandler {
private Person person;
public PersonInvocationHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Hi!");
return method.invoke(person, args);
}
}
இப்போது invoke() முறையில் அசல் முறையில் அழைப்பைச் சேர்த்துள்ளோம். நாம் இப்போது எங்கள் முந்தைய எடுத்துக்காட்டில் இருந்து குறியீட்டை இயக்க முயற்சித்தால்:
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
// Create the original object
Man arnold = new Man("Arnold", 30, "Thal", "Austria");
// Get the class loader from the original object
ClassLoader arnoldClassLoader = arnold.getClass().getClassLoader();
// Get all the interfaces that the original object implements
Class[] interfaces = arnold.getClass().getInterfaces();
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
// Call one of our original object's methods on the proxy object
proxyArnold.introduce(arnold.getName());
}
}
இப்போது எல்லாம் சரியாக செயல்படுவதைப் பார்ப்போம் :) கன்சோல் வெளியீடு:
Hi! My name is Arnold
உங்களுக்கு இது எப்போது தேவைப்படலாம்? உண்மையில், அடிக்கடி. "டைனமிக் ப்ராக்ஸி" வடிவமைப்பு முறை பிரபலமான தொழில்நுட்பங்களில் தீவிரமாகப் பயன்படுத்தப்படுகிறது... ஓ, டைனமிக் ப்ராக்ஸி ஒரு வடிவமைப்பு முறை என்பதை நான் குறிப்பிட மறந்துவிட்டேன்! வாழ்த்துக்கள், நீங்கள் இன்னும் ஒன்றைக் கற்றுக்கொண்டீர்கள்! :) 
// Create a proxy for our arnold object
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
இங்கே நாம் நபர் இடைமுகத்திற்காக குறிப்பாக ப்ராக்ஸியை உருவாக்குகிறோம் . வகுப்பிற்கான ப்ராக்ஸியை உருவாக்க முயற்சித்தால், அதாவது குறிப்பு வகையை மாற்றி, மேன் வகுப்பிற்கு அனுப்ப முயற்சித்தால், அது வேலை செய்யாது.
Person proxyArnold = (Person) Proxy.newProxyInstance(arnoldClassLoader, interfaces, new PersonInvocationHandler(arnold));
proxyArnold.introduce(arnold.getName());
இழை "முக்கிய" java.lang இல் விதிவிலக்கு ப்ராக்ஸிகள் இடைமுகங்களுடன் வேலை செய்கின்றன. இன்னைக்கு அவ்வளவுதான் :) சரி, இப்போ கொஞ்சம் டாஸ்க்குகளை தீர்த்து வைத்தால் நன்றாக இருக்கும்! :) அடுத்த முறை வரை!
GO TO FULL VERSION