Spring AOP

Spring AOP

理解advice,pointcut和advisor.
advice是想向别的程序内部不同的地方注入的代码.
pointcut定义了需要注入advice的位置.
advisor是pointcut和advice的装配器,是将advice注入主程序中预定义位置的代码.

spring提供的几个种同的advices,比如before advice,after advice,around advice,throw advice等等.

 

业务接口IHello.java

 

public interface IHello {
	public void toHello(String name);
}

 

实现HelloImp.java

 

public class HelloImp implements IHello {

	public void toHello(String name) {
		System.out.println("hello:" + name);
	}

}

 

以下是几种advices的实现:

 

1. 1. before advice 会在目标对象被调用之前执行的.before advice的实现代码:

 

LogBeforeAdvice.java

 

public class LogBeforeAdvice implements MethodBeforeAdvice {

	public void before(Method method, Object[] param, Object target)
			throws Throwable {
		System.out.println("method start..." + method.getName());
		
	}
}

接口MethodBeforeAdvice只有一个方法before需要实现,它定义了advice的实现.
before方法有三个参数,参数Method是advice开始后执行的方法.Object[]是传给被调用的参数数组,Object是执行方法m对象的引用.


2. after advice 会在目标对象被调用之后执行的.after advice的实现代码:

 

public class LogAfterAdvice implements AfterReturningAdvice {

	public void afterReturning(Object arg0, Method method, Object[] arg2,
			Object arg3) throws Throwable {
		
		System.out.println("method end..." + method.getName() + arg2[0]);
		
	}

}

 

spring的配置:

 

<bean id="logBeforeAdvice" class="com.spring.advices.LogBeforeAdvice"></bean>
	
<bean id="hello" class="com.dynamic.proxy.HelloImp"></bean>
	
<bean id="logAfterAdvice" class="com.spring.advices.LogAfterAdvice"></bean>
	
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces">
		<value>com.dynamic.proxy.IHello</value>
	</property>
		
	<property name="target">
		<ref bean="hello"/>
	</property>
		
	<property name="interceptorNames">
		<list>
			<value>logBeforeAdvice</value>
			<value>logAfterAdvice</value>
		</list>
	</property>
</bean>

 

 

属性proxyInterface定义了接口类。
   属性target指向本地配置的一个bean
   属性interceptorNames是唯一允许定义一个值列表的属性.这个列表包含所有需要在beanTarget上执行的advice.
 

编写主方法的Java代码:

 

public class SpringDemo {
		public static void main(String[] args) {
			
			ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
			
			IHello hello = (IHello)context.getBean("helloProxy");
			
			hello.toHello("callan");
		}
	}

每次toHell方法调用时,都会执行advice.也就是说调用toHello会先执行LogAfterAdvice,调用完后会执行LogAfterAdvice
   
   
    以上是before advice和after advice的实现,也可以单独用MethodInterceptor来代替它们的功能.不同的是,在MethodInterceptor的invoke()方法中你要决定是否使用    proceed()方法来调用目标方法.

 

3. around advice的实现:

 

 public class LogInterceptor implements MethodInterceptor {

		public Object invoke(MethodInvocation method) throws Throwable {
			// TODO Auto-generated method stub
			
			System.out.println("start...");
			
			Object obj = null;
			
			// method.proceed()会调用目示方法,在调用目录方法之前打印了start,之后打印了end,实现与before,after的组合功能
			obj = method.proceed();
			
			System.out.println("end...");
			
			return obj;
		}

	}

 

配置与before,after相似

 

<bean id="helloProxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces">
		<value>com.dynamic.proxy.IHello</value>
	</property>
		
	<property name="target">
		<ref bean="hello"/>
	</property>
		
	<property name="interceptorNames">
		<list>
			<value>logInterceptore</value>
		</list>
	</property>
</bean>

 

before advice,after advice,around advice三种只定义了切入在代理接口执行前后执行,其实可以还可以更细的切入日志等

 

4. 有一个方便的类叫做NameMatchMethodPointcutAdvisor,它允许通过名称选择方法,只有匹配的方法才会加入日志.要想使用NameMatchMethodPointcutAdvisor,只需要修改配置.

 

<bean id="helloAdvice" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
	<property name="mappedName">
		<value>toHello</value>   <!-- 方法名 -->
	</property>
		
	<property name="advice">
		<ref bean="logBeforeAdvice"/>
	</property>
</bean>
    
    <bean id="helloProxy3" class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="proxyInterfaces">
		<value>com.dynamic.proxy.IHello</value>
	</property>
		
	<property name="target">
		<ref bean="hello"/>
	</property>
		
	<property name="interceptorNames">
		<list>
			<value>helloAdvice</value>
		</list>
	</property>
</bean>

 

IHello接口中,只有toHello方法才能切入日志.
    mappedName是定义匹配的方法名,还可以使用mappedNames定义方法列表
    <property name="mappedNames">
      <value>toHello</value>   <!-- 方法名 -->
      <value>toHello2</value>   <!-- 方法名 -->
      <value>toHello3</value>   <!-- 方法名 -->
    </property>

 

5.  RegExpMethodPointcutAdvisor与NameMatchMethodPointcutAdvisor类例,只需要修改配置.

 

<bean id="reg" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
	<property name="pattern">
		<value>.*hello</value>
	</property>
		
	<property name="advice">
		<list>
			<value>logInterceptore</value>
		</list>
	</property>
</bean>

pattern属性符合完整类名加方法名称.比如IHello下的toHello方法,就要编写com.dynamic.proxy.IHello.toHello.
 
 .  符合任何单一字符 
 +   符合前一个字符一次或多次
 *  符合前一个字符零次或多次
 
 
 6.如果要为目标对象提供advice,必须要为其建立代理对象,如果程序规模很大时,一个个代理会很麻烦,spring提供了自动代理BeanNameAutoProxyCreator与  DefaultAdvisorAutoProxyCreator
  
   BeanNameAutoProxyCreator:根据beanName进行自动代理.
  
    spring配置:

 <?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean id="logBeforeAdvice" class="com.spring.advices.LogBeforeAdvice"></bean>
			
<bean id="helloService" class="com.dynamic.proxy.HelloImp">
</bean>

<bean id="beanNameAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
	<property name="beanNames">
		<list>
			<value>*Service</value>
		</list>
	</property>
				
	<property name="interceptorNames">
		<value>logBeforeAdvice</value>
	</property>
</bean>
</beans>

 

为每个beanName为Service结属的bean提供自动的代理.

public class SpringDemo {
	public static void main(String[] args) {
				
		ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
				
		IHello hello = (IHello)context.getBean("helloService");
				
		hello.toHello("callan");
}
		}

这样在toHello方法调用前也会执行logBeforeAdvice,以后只要想要为目标对象使用log advice时,只要取名为***Service就可以了

你可能感兴趣的:(spring,AOP,bean,xml,idea)