2015-12-19 30 views
6

Mam kilka prostych interfejsów z programami pobierającymi i ustawiającymi oraz kilka innych metod do odczytu i zapisu z systemu plików. Używając bezpośrednio kodu Java, mógłbym napisać pojedynczą "procedurę wywoływania" i użyć jej do utworzenia instancji obiektów dla wszystkich tych interfejsów (nie próbowałem tego, ale myślę, że można to zrobić).Implementuje interfejs Java za pomocą Spring (AOP?)

Zastanawiam się, czy można zrobić to samo za pomocą Spring.

Poniższy kod implementuje dany interfejs. Jak łatwo zauważyć, ten sam program obsługi wywołania może być użyty dla dowolnego interfejsu.

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 

public class AOPTester { 

    public static void main(String[] args) { 
     InvocationHandler handler = new MyInvocationHandler(); 
     AnyInterface proxy = (AnyInterface) Proxy.newProxyInstance(
            AnyInterface.class.getClassLoader(), 
            new Class[] { AnyInterface.class }, 
            handler); 

     proxy.sayHello(); 

    } 

} 

interface AnyInterface { 
    public void sayHello(); 
} 

class MyInvocationHandler implements InvocationHandler{ 

    public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
     System.out.println("Hello!"); 

     return null; 
    } 
} 
+0

Coś podobnego tutaj: [http://stackoverflow.com/questions/34133189/mongodb-dao-sets-all-attributes-to-null-before-save/34160666 ? noredirect = 1] (http://stackoverflow.com/questions/34133189/mongodb-dao-sets-all-attributes-to-null-before-save/34160666?noredirect=1) – Valijon

+0

Przepraszam, @Valijon, I nie rozumiem, dlaczego ten adres URL powinien być w jakiś sposób powiązany z tym, co muszę zrobić. –

+0

'Interfejsy' nie wykonują żadnej logiki, wystarczy zdefiniować umowę interfejsu usługi.Najpierw musisz zdefiniować implementację interfejsu w kodzie Java. Następnie, jeśli nie chcesz zainicjować tej implementacji kilka razy, możesz pobrać 'singleton' z kontekstu. W tym łączu znajduje się kilka interfejsów, takich jak 'Dao',' MongoOperations ', w których implementacja jest odzyskiwana z kontekstu. Wiosna pomaga ci inicjować klasy, a nie definiować składnię implementacji (w jaki sposób skompilowałaby się w kod bajtowy?). – Valijon

Odpowiedz

0

Jest rzeczywiście czysty sposób, aby to zrobić wiosną za pomocą ProxyFactoryBean. W poniższym przykładzie ta klasa jest inicjowana bez komponentu bean celu. Utworzony obiekt nie ma żadnego celu do przekazywania żądań, ale może implementować dowolny interfejs, jak każdy inny serwer proxy w Javie.

Oczywiście, jeśli spróbujesz wywołać metodę continue na obiekcie wywołania przekazanym do metody invoke MethodInterceptor, otrzymasz wyjątek NullPointerException.

lepiej aplikacji context.xml:

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> 

    <bean id="goodbyeMethodInterceptor" class="com.someco.GoodbyeMethodInterceptor" /> 

    <bean name="goodbyeProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> 
     <property name="interfaces"> 
      <list> 
       <value>com.someco.AnyInterface</value> 
      </list> 
     </property> 
     <property name="interceptorNames"> 
      <list> 
       <value>goodbyeMethodInterceptor</value> 
      </list> 
     </property> 
    </bean> 
</beans> 

GoodbyeMethodInterceptor:

package com.someco; 

import org.aopalliance.intercept.MethodInvocation; 

public class GoodbyeMethodInterceptor implements org.aopalliance.intercept.MethodInterceptor { 

    public Object invoke(MethodInvocation invocation) throws Throwable { 
     System.out.println("Goodbye"); 

     return null; 
    } 

} 

ProxyTester:

package com.someco; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

import com.someco.AnyInterface; 

public class ProxyTester { 

    public static void main(String[] args) { 
     ApplicationContext context = new ClassPathXmlApplicationContext("better-application-context.xml"); 
     AnyInterface tester = (AnyInterface) context.getBean("goodbyeProxy"); 
     tester.sayHello(); 
    } 
} 

AnyInterface:

package com.someco; 

public interface AnyInterface { 
    public void sayHello(); 
} 

Podstawowe pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.someco</groupId> 
    <artifactId>proxy-tester</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>main</name> 
    <url>http://maven.apache.org</url> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <spring.version>3.0.5.RELEASE</spring.version> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-core</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
    </dependencies> 
</project> 
2

Następująca konfiguracja powinna działać (użyłem twoich zajęć, ale przeniosłem je do innej paczki tylko po to, aby kod był bardziej czytelny). Użyłem kontekstu sprężyny, aby wykonać to samo połączenie z metodą fabryczną newProxyInstance(), której użyłeś.

<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> 

    <bean id="pojoInvocationHandler" class="com.someco.PojoInvocationHandler"></bean> 

    <bean id="AnyInterfaceClass" class="java.lang.Class" factory-method="forName"> 
     <constructor-arg value="com.someco.AnyInterface"/> 
    </bean> 

    <bean id="anyInterface" class="java.lang.reflect.Proxy" factory-method="newProxyInstance"> 
     <constructor-arg> 
      <bean 
       factory-bean="AnyInterfaceClass" 
       factory-method="getClassLoader" /> 
     </constructor-arg> 
     <constructor-arg> 
      <list> 
       <ref bean="AnyInterfaceClass" /> 
      </list> 
     </constructor-arg> 
     <constructor-arg ref="pojoInvocationHandler"/> 
    </bean> 
</beans> 

ProxyTester:

package com.someco; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Proxy; 

import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

import com.someco.AnyInterface; 

public class ProxyTester { 

    public static void main(String[] args) { 
     ApplicationContext contex = new ClassPathXmlApplicationContext("application-context.xml"); 
     AnyInterface tester = (AnyInterface) contex.getBean("anyInterface"); 
     tester.sayHello(); 

     /* Implemented with the previous code */ 
//  callProxy(); 
    } 

    /** 
    * @deprecated 
    * explanation of why function was deprecated, if possible include what 
    * should be used. 
    */ 
    @Deprecated 
    public static void callProxy() { 
     InvocationHandler handler = new PojoInvocationHandler(); 
     AnyInterface proxy = (AnyInterface) Proxy.newProxyInstance(
            AnyInterface.class.getClassLoader(), 
            new Class[] { AnyInterface.class }, 
            handler); 
     proxy.sayHello(); 
    } 

} 

PojoInvocationHandler:

package com.someco; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 

public class PojoInvocationHandler implements InvocationHandler{ 

    public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
     System.out.println("Hello!"); 

     return null; 
    } 
} 

AnyInterface:

package com.someco; 

public interface AnyInterface { 
    public void sayHello(); 
} 

Podstawowe pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.someco</groupId> 
    <artifactId>proxy-tester</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>main</name> 
    <url>http://maven.apache.org</url> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <spring.version>3.0.5.RELEASE</spring.version> 
    </properties> 

    <dependencies> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-core</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>${spring.version}</version> 
     </dependency> 
    </dependencies> 
</project> 
+2

To wygląda obiecująco, chociaż szukałem znacznie bardziej kompaktowej konfiguracji. –

+2

Można zaimplementować klasę statyczną metodą, która ma tylko dwa parametry: "AnyInterfaceClass" i program obsługi wywołania. To właśnie zamierzam spróbować dla siebie. –

+2

Dzięki! Nie będę odpowiadał na pytanie, czy ktoś ma lepsze rozwiązanie. –