1
2
3
4
5
6
7
8
|
public interface InventoryService { public Inventory create(Inventory inventory); public List<Inventory> list(); public Inventory findByVin(String vin); public Inventory update(Inventory inventory); public boolean delete(Long id); public Inventory compositeUpdateService(String vin, String newMake); } |
Шаги для создания динамического прокси-сервера для экземпляров этого интерфейса следующие:
1. Создайте экземпляр java.lang.reflect.InvocationHandler , он будет отвечать за обработку вызовов методов от имени фактического экземпляра службы, пример обработчика вызова для аудита:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
... public class AuditProxy implements java.lang.reflect.InvocationHandler { private Object obj; public static Object newInstance(Object obj) { return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), new AuditProxy(obj)); } private AuditProxy(Object obj) { this .obj = obj; } public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Object result; try { logger.info( "before method " + m.getName()); long start = System.nanoTime(); result = m.invoke(obj, args); long end = System.nanoTime(); logger.info(String.format( "%s took %d ns" , m.getName(), (end-start)) ); } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException( "unexpected invocation exception: " + e.getMessage()); } finally { logger.info( "after method " + m.getName()); } return result; } } |
2. При создании экземпляров InventoryService возвращайте прокси-сервер, который в данном случае является AuditProxy, составляя экземпляры InventoryService, что можно лучше объяснить с помощью UML:
Вот как это будет выглядеть в коде:
1
|
InventoryService inventoryService = (InventoryService)AuditProxy.newInstance( new DefaultInventoryService()); |
Теперь любые вызовы inventoryService будут выполняться через экземпляр AuditProxy, который будет измерять время, затраченное на метод, при делегировании фактического вызова метода экземпляру InventoryService.
Итак, для чего используются прокси:
1. Spring AOP использует его широко — он внутренне создает динамический прокси для различных конструкций AOP
2. Как в этом примере, для любого украшения класса — АОП определенно будет лучше подходить для такого случая использования, хотя
3. Для любых сред, нуждающихся в поддержке функций на основе интерфейса и аннотаций. Реальный прокси-экземпляр даже не должен существовать, динамический прокси-сервер может воссоздать ожидаемое поведение интерфейса на основе некоторых метаданных, предоставляемых аннотациями.
Ссылка: Создание динамического прокси Java от нашего партнера по JCG Биджу Кунджуммена в блоге all and sundry.