五.
Spring-Aop
引入的介绍
下面我们介绍一种通知“引入”,关于引入,如同它的名字一样,给对象添加方法和属性。呵呵,好厉害吧。它是通过CBLIB来动态生成类的,所以自己用的时候别忘了加载这个包。
代码:
购物时候放东西的包包;
public interface CustomerBag {
void addBag(Object obj);
void clean();
int getCount();
}
我们要给别的对象类添加的Mixin,嘿嘿。
public class CustomerMixin extends DelegatingIntroductionInterceptor implements CustomerBag {
private static final long serialVersionUID = 5296015143432822715L;
private ArrayList bag = new ArrayList();
public void addBag(Object obj) {
bag.add(obj);
}
public void clean() {
bag = new ArrayList();
}
public ArrayList getBag() {
return bag;
}
public int getCount() {
return bag.size();
}
}
我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="customer" class="demo.Customer" singleton="false" />
<bean id="customerMixin" class="demo.CustomerMixin" singleton="false" />
<bean id="customerMixinAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
singleton="false">
<constructor-arg>
<ref bean="customerMixin" />
</constructor-arg>
</bean>
<bean id="customerBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyTargetClass" value="true" />
<property name="singleton" value="false" />
<property name="interceptorNames">
<list>
<value>customerMixinAdvisor</value>
</list>
</property>
<property name="target">
<ref bean="customer" />
</property>
</bean>
</beans>
修改我们的RunDemo类,添加一个方法:
/**
*
创建引用通知;
*/
public static void customer() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/customer.xml");
//
这个类是有CGLIB动态生成的;
Customer bag = (Customer) context.getBean("customerBean");
CustomerBag bag2 = (CustomerBag) bag;
bag2.addBag(new Object());
System.out.println(bag.getName());
System.out.println(bag2.getCount());
}
在main中调用这个方法,运行,结果如下:
悠~游!
1
在这里我要说明一下,关于引入这个通知的使用我仅仅是看了一眼,具体的例子可能有不恰当之处还请高手们指点。
六.
Spring-Aop
之 BeanNameAutoProxyCreator
BeanNameAutoProxyCreator
看其名,大概知道其意。根据bean的名字自动匹配拦截代理,让我们看看它能带来什么?
代码:
public class PerformanceThresholdInterceptor implements MethodInterceptor {
private final long thresholdInMillis;
PerformanceThresholdInterceptor(long time) {
thresholdInMillis = time;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("
开始测试时间.");
long t = System.currentTimeMillis();
Object o = invocation.proceed();
t = System.currentTimeMillis() - t;
if (t > thresholdInMillis) {
System.out.println("
警告:调用的方法所耗费的时间超过预警时间(" + thresholdInMillis + " 微秒)");
}
System.out.println("
测试时间结束.");
return o;
}
}
这个又是自定义的,呵呵。我们继承MethodInterceptor这换类,实现我们自己的方法过滤器。具体要实现的功能就是检验我们要调用的方法,和OnePerCustomerInterceptor这个类一样。
接下来是我们的xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
<bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
<constructor-arg>
<value>5000</value>
</constructor-arg>
</bean>
<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Target</value>
</list>
</property>
<property name="interceptorNames">
<value>performanceThresholdInterceptor</value>
</property>
</bean>
</beans>
/**
*
创建beanNameAutoProxyCreator动态代理;
*/
public static void beanNameProxy() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/beanNameProxy.xml");
KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
try {
akem.buyCheese(new Customer());
} catch (KwikEMartException e) {
e.printStackTrace();
}
}
运行我们的例子,结果如下:
开始测试时间.
--我想买:奶酪!
测试时间结束.
看到了么?Spring aop自动寻找Bean的名字为*
Target
的类,进行方法过滤。呵呵,可能你会说这个有什么用?自己写不也一样么?其实如果系统变得庞大的话,自己配置也是十分耗费精力的。
七.
Spring-Aop DefaultAdvisorAutoProxyCreator
接下来我们将介绍更加强大的一个代理器:DefaultAdvisorAutoProxyCreator。
DefaultAdvisorAutoProxyCreator
和BeanNameAutoProxyCreator不同的是,DefaultAdvisorAutoProxyCreator只和Advisor 匹配,所以我们写一个Advisor到xml文档中去。
XML
文档如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="kwikEMartTarget" class="demo.ApuKwikEMart"></bean>
<bean id="performanceThresholdInterceptor" class="demo.advice.PerformanceThresholdInterceptor">
<constructor-arg>
<value>5000</value>
</constructor-arg>
</bean>
<!--
使用RegexpMethodPointcutAdvisor来匹配切入点完成个一个Advisor; -->
<bean id="regexpFilterPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern">
<!--
匹配的名字为方法名;
-->
<value>.*buy.*</value>
</property>
<property name="advice">
<ref bean="performanceThresholdInterceptor"/>
</property>
</bean>
<bean id="defaultAdvisorAutoProxyCreator"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
</beans>
/**
*
创建defaultAdvisorAutoProxyCreator动态代理;
*/
public static void defaultAdvisorProxy() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/defaultAdvisorProxy.xml");
KwikEMart akem = (KwikEMart) context.getBean("kwikEMartTarget");
try {
akem.buyCheese(new Customer());
} catch (KwikEMartException e) {
e.printStackTrace();
}
}
运行,结果如下:
开始测试时间.
--我想买:奶酪!
测试时间结束.
八.
Spring-Aop TargetSources
介绍
1.
可热交换的目标源
可热交换的目标源主要是在你程序运行中切换目标对象,而此时调用者引用的对象也会自动切换。具体的概念你可以参考Spring-Reference关于它的介绍,我们主要在程序中体会它给我们带来的改变。
修改我们的xml成为下面的样子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="kwikEMartTarget" class="demo.ApuKwikEMart" ></bean>
<bean id="swapApuKwikEMart" class="demo.SwapApuKwikEMart" singleton="false"></bean>
<bean id="onePerCustomerInterceptor" class="demo.advice.OnePerCustomerInterceptor" />
<bean id="nameMatchfilterPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName">
<value>buy*</value>
</property>
</bean>
<bean id="runDemofilterPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut">
<ref bean="nameMatchfilterPointcut" />
</property>
<property name="advice">
<ref bean="onePerCustomerInterceptor" />
</property>
</bean>
<bean id="swappable" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg><ref local="kwikEMartTarget"/></constructor-arg>
</bean>
<bean id="kwikEMart" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="demo.KwikEMart" />
<property name="interceptorNames">
<list>
<value>runDemofilterPointcutAdvisor</value>
</list>
</property>
<property name="targetSource">
<ref bean="swappable" />
</property>
</bean>
</beans>
代码:
切换后的对象
public class SwapApuKwikEMart implements KwikEMart {
private boolean cheeseIsEmpty = false;
private boolean pepperIsEmpty = false;
private boolean squishIsEmpty = false;
public Cheese buyCheese(Customer customer) throws KwikEMartException {
if (cheeseIsEmpty) {
throw new NoMoreCheeseException();
}
Cheese s = new Cheese();
System.out.println("--
我不是ApuKwikEMart,我想买:" + s);
return s;
}
public Pepper buyPepper(Customer customer) throws KwikEMartException {
if (pepperIsEmpty) {
throw new NoMorePepperException();
}
Pepper s = new Pepper();
System.out.println("--
我不是ApuKwikEMart,我想买:" + s);
return s;
}
public Squish buySquish(Customer customer) throws KwikEMartException {
if (squishIsEmpty) {
throw new NoMoreSquishException();
}
Squish s = new Squish();
System.out.println("--
我不是ApuKwikEMart,我想买:" + s);
return s;
}
public void setCheeseIsEmpty(boolean cheeseIsEmpty) {
&n