2

这里的目的是处理资源的混淆密码。

我们有一个 Advisor 拦截对 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,这意味着顾问将不会完成它的工作。

那么,这个呢:

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

没有。Spring 抱怨 ProxyFactoryBean 没有密码属性。当然,事实并非如此。具有密码属性的东西是工厂 bean创建的东西。

布勒?

4

2 回答 2

1

我的第一次努力很糟糕,但我很着急。我道歉。现在我想我知道它应该如何工作了,因为我相信我自己已经实现了你想要的。

我从一个 Credential 类开始(注意:没有接口):


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


我需要 DecryptorAdvice 来实现 Spring 的 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. 如果我使用 new 创建一个不受 Spring 控制的对象,则不会应用建议。
  2. 如果我在初始化应用上下文之前在 ctor 中调用 setPassword,则不会应用建议。
  3. 如果我在应用上下文初始化后在我的代码中调用 setPassword,则会应用建议。

我希望这可以帮助你。

于 2009-01-08T01:09:22.810 回答
0

我以为您希望 beforeMethod 建议使用传递给 setPassword 方法的加密密码字符串。您想解密它并让建议的班级获得解密版本。

我也没有在您的代理工厂中看到代理接口设置。“Spring In Action”说“......使用接口创建代理比代理类更受欢迎......”代理类应该是例外,而不是规则。

发布您的建议课程。

于 2009-01-07T22:23:20.790 回答