Spring AOP: применение свойств через аспект - PullRequest
2 голосов
/ 08 января 2009

Намерение здесь состоит в том, чтобы иметь дело с запутанными паролями для ресурсов.

У нас есть советник, который перехватывает вызовы setPassword и расшифровывает аргумент.

Мы создали шаблон, который выглядит примерно так:

<bean id="pwAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
   <property name="advice"><bean class="our.advice.bean.class"/></property>
   <property name="mappedName" value="setPassword"/>
</bean>
<bean id="passwordHandlerTemplate" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
   <property name="interceptorNames"><list><value>pwAdvisor</value></list></property>
</bean>

У меня нет точного синтаксиса, чтобы использовать его. Наиболее очевидный способ:

<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
   <property name="target">
      <bean class="the.target.class.name">
         <property name="password" value="encrypted garbage"/>
      </bean>
    </property>
 </bean>

Но это не работает правильно, поскольку свойство пароля применяется к внутреннему компоненту, что означает, что советник не будет выполнять свою работу.

Ну, а как же это:

<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
   <property name="target"><bean class="the.target.class.name"/></property>
   <property name="password" value="encrypted garbage"/>
</bean>

Неа. Спринг жалуется, что у ProxyFactoryBean нет свойства пароля. И, конечно же, это не так. То, что имеет свойство пароля, это то, что фабричный бин создает .

Bueller

Ответы [ 2 ]

1 голос
/ 08 января 2009

Мое первое усилие было плохим, но я торопился. Приношу извинения. Теперь я думаю, что знаю, как это должно работать, потому что я считаю, что я сам реализовал то, что вы хотите.

Я начал с класса учетных данных (примечание: нет интерфейса):


package aop;

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

public class Credential
{
   private static final String DEFAULT_USERNAME = "username";
   private static final String DEFAULT_PASSWORD = "password";

   private String username;
   private String password;

   public static void main(String[] args)
   {
      Credential cred1 = new Credential("foo", "bar");
      System.out.println("created using new: " + cred1);

      ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop-context.xml");
      Credential cred2 = (Credential) context.getBean("credential");

      System.out.println("created using app context: " + cred2);

      String password = ((args.length > 0) ? args[0] : "baz");
      cred2.setPassword(password);

      System.out.println("initialized using setter: " + cred2);      
   }

   public Credential()
   {
      this(DEFAULT_USERNAME, DEFAULT_PASSWORD);
   }

   public Credential(String username, String password)
   {
      this.setUsername(username);
      this.setPassword(password);
   }

   public String getUsername()
   {
      return username;
   }

   public void setUsername(String username)
   {
      this.username = username;
   }

   public String getPassword()
   {
      return password;
   }

   public void setPassword(String password)
   {
      this.password = password;
   }


   public String toString()
   {
      return new StringBuilder().append("Credential{").append("username='").append(username).append('\'').append(", password='").append(password).append('\'').append('}').toString();
   }
}

Я создал интерфейс Decryptor:


package aop;

public interface Decryptor
{
   String decrypt(String encrypted);
}

И DecryptorImpl:


package aop;

public class DecryptorImpl implements Decryptor
{
   public static final String DEFAULT_DECRYPTED_VALUE = " - not secret anymore";

   public String decrypt(String encrypted)
   {
      // Any transform will do; this suffices to demonstrate
      return encrypted + DEFAULT_DECRYPTED_VALUE;
   }
}

1012 *
*

Мне нужен DecryptorAdvice для реализации SpringB MethodBeforeAdvice:



package aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class DecryptionAdvice implements MethodBeforeAdvice
{
   private Decryptor decryptor;


   public DecryptionAdvice(Decryptor decryptor)
   {
      this.decryptor = decryptor;
   }

   public void before(Method method, Object[] args, Object target) throws Throwable
   {
      String encryptedPassword = (String) args[0];

      args[0] = this.decryptor.decrypt(encryptedPassword);
   }
}

И я связал это вместе в aop-context.xml. (Если вы скажете мне, как заставить XML отображаться, я опубликую его.) Обратите внимание на passwordDecryptionAdvisor: он соответствует только методу setPassword.

Интересная часть происходит, когда я запускаю его. Вот что я вижу в консоли:


created using new: Credential{username='foo', password='bar'}
created using app context: Credential{username='stackoverflow', password='encrypted-password'}
initialized using setter: Credential{username='stackoverflow', password='baz - not secret anymore'}

Что это говорит мне:

  1. Если я создаю объект с новым не под контролем Spring, совет не применяется.
  2. Если я вызову setPassword в ctor до того, как контекст приложения инициализирован, совет не применяется.
  3. Если я позвоню setPassword в моем коде после того, как контекст приложения инициализировано, совет прилагается.

Надеюсь, это поможет вам.

0 голосов
/ 08 января 2009

Я думал, что вы хотели, чтобы совет beforeMethod использовал зашифрованную строку пароля, которая передается в метод setPassword. Вы хотите расшифровать это и попросите рекомендованный класс получить расшифрованную версию.

Я также не вижу прокси-интерфейса, установленного на вашей фабрике прокси. «Spring In Action» говорит: «Создание прокси с интерфейсами предпочтительнее прокси-классов ...» Прокси-классы должны быть исключением, а не правилом.

Опубликуйте свой совет.

...