2015-12-19 17 views
6

Ho diverse interfacce semplici con getter e setter e alcuni altri metodi per leggere e scrivere dal file system. Usando direttamente il codice Java, potrei scrivere un singolo "gestore di invocazione" e usarlo per istanziare oggetti per tutte queste interfacce (non l'ho provato, ma penso che potrebbe essere fatto).Implementa un'interfaccia Java utilizzando Spring (AOP?)

Mi chiedo se sia possibile fare lo stesso utilizzando Spring.

Il codice seguente implementa un'interfaccia specifica. Come si può facilmente vedere, lo stesso stesso gestore di invocazione può essere utilizzato per qualsiasi interfaccia.

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

Qualcosa di simile qui: [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

Mi dispiace @Valijon, I Non vedo perché quell'URL dovrebbe essere in qualche modo correlato con quello che devo fare. –

+0

'Interfacce' non fanno alcuna logica, basta definire il contratto dell'interfaccia di servizio.Quindi, in primo luogo, è necessario definire l'implementazione dell'interfaccia nel codice Java. Quindi, se non si desidera avviare tale implementazione più volte, è possibile recuperare un 'singleton' dal contesto. In quel collegamento, ci sono diverse interfacce, come 'Dao', 'MongoOperations' in cui l'implementazione viene ripristinata dal contesto. Spring ti aiuta solo a iniziare le tue classi, non a definire la sintassi dell'implementazione (come verrebbe compilata in byte-code?) – Valijon

risposta

0

C'è in realtà un modo pulito per farlo con Spring utilizzando ProxyFactoryBean. Nell'esempio seguente questa classe è inizializzata senza un bean di destinazione. L'oggetto creato non ha alcuna destinazione per l'inoltro delle richieste, ma può implementare qualsiasi interfaccia come qualsiasi altro proxy in Java.

Ovviamente, se si tenta di chiamare il metodo di procedere sull'oggetto di chiamata passato al metodo invoke di MethodInterceptor, si otterrà NullPointerException.

meglio-application-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(); 
} 

pom.xml base:

<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

La seguente configurazione dovrebbe funzionare per voi (ho usato le vostre classi ma le ho spostate in un pacchetto diverso solo per rendere il codice più leggibile). Ho usato il contesto di primavera per eseguire la stessa chiamata al metodo factory newProxyInstance() che avete usato.

<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(); 
} 

pom.xml base:

<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

Questo sembra promettente anche se, stavo cercando una configurazione molto più compatta. –

+2

È possibile implementare una classe con un metodo statico che ha solo due parametri: "AnyInterfaceClass" e il gestore di chiamata. Questo è quello che cercherò per me stesso. –

+2

Grazie! Non metterò la domanda come risposta solo per vedere se qualcuno ha una soluzione migliore. –