Spring的AOP思想和实践

引言

       大家都知道Spring中最最牛逼的就是IOC/DI :控制反转/依赖注入,AOP: 面向切面编程,两个核心,如果说Spring是一个牛逼的框架,不如它是一个思想的引导者,Spring中思想很重要,条例整清楚了,即便是记不住其中的API,但是只要看到,便有一种水到渠成的感觉。

       再次认识到,学习是一个需要不断反复的过程,不论当初记的有多深刻,只要一段时间不用不看,很快就会忘记,所以在此记录学习的过程,希望日后多来看看,相信会有记住的一天!

       下面是学习spring中AOP的一些笔记,从底层到企业中的应用,一步一个脚印,一步一个Demo


一:因为spring中AOP应用的是代理,所以先来复习一下代理的知识


  JDK动态代理

/**
 * 代理类接口
 * @author zhaofx
 *
 */
public interface DogService {

	public void run();
	
	public void eat();
}

/**
 * 被代理类实现
 * @author zhaofx
 *
 */
public class DogServiceImpl implements DogService{

	@Override
	public void run(){
		System.out.println("dog...run。。。。");
	}
	@Override
	public void eat() {
		System.out.println("dog...eat。。。。");
	}
}

/**
	 * JDK动态代理,被代理类必须有接口
	 */
	@Test
	public void test2(){
		final DogService dogService = new DogServiceImpl();
		/**
		 * @Param:类加载器,jdk提供三种类加载器
		 * @Param:被代理类的接口,JDK动态代理必须要有接口
		 * @Param:此处是一个匿名内部类,也可以是一个Implement(实现)了InvocationHandler接口的子类对象
		 */
		DogService dogServiceProxy = (DogService)Proxy.newProxyInstance(TestAop.class.getClassLoader(),dogService.getClass().getInterfaces() , new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				System.out.println("方法前增强。。。。");
				//***切记,此处第一个参数应该是被代理对象,而非代理后proxy 对象,如果填proxy将不限循环,一直执行已经被代理的方法
				method.invoke(dogService, args);
				System.out.println("方法后增强");
				return proxy;
			}
		});
		dogServiceProxy.run();
		//**** getClass 方法永远不会被代理,通过这个方法可以看到此对象是被代理点对象,并且是JDK动态代理的
		System.out.println(dogServiceProxy.getClass());
	}

方法前增强。。。。
dog...run。。。。
方法后增强

class $Proxy4


 CGlib动态代理

	/**
	 * CGlib动态代理
	 * 和JDK动态代理最大的区别是 CGlib代理,被代理类可以没有接口
	 * 
	 */
	@Test
	public void test3(){
		final DogServiceImpl dogServiceImpl = new DogServiceImpl();
		
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(dogServiceImpl.getClass());
		enhancer.setCallback(new MethodInterceptor() {
			
			@Override
			public Object intercept(Object proxy, Method method, Object[] arg,
					MethodProxy methodProxy) throws Throwable {
				System.out.println("方法前增强");
				methodProxy.invoke(dogServiceImpl, arg);
				System.out.println("方法后增强");
				method.invoke(dogServiceImpl, arg); //此method是原生method不增强
				return proxy;
			}
		});
		DogServiceImpl dogServiceImpl2 = (DogServiceImpl) enhancer.create();
		dogServiceImpl2.run();
		//**** getClass 方法永远不会被代理,通过这个方法可以看到此对象是被代理点对象,并且是用CGlib代理的
		System.out.println(dogServiceImpl2.getClass());
	}

方法前增强
dog...run。。。。
方法后增强
dog...run。。。。
class cn.aop.service.impl.DogServiceImpl $  $ EnhancerByCGLIB$$8530829c

使用ProxyFactoryBean代理目标类所有方法,太死

/**
 * MethodBeforeAdvice 为前置通知
 * @author zhaofx
 *
 */
public class DogAdvice  implements MethodBeforeAdvice{
	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("before.....");
	}
}

<?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.xsd">
	   <!-- 
	   		用 Spring的ProxyFactoryBean代理Bean ,此方式只能代理目标Bean的所有方法,
	   		并且目标Bean需要一个个配置到ProxyFactoryBean代理Bean工厂下
	    -->
	 <!-- 被代理的类 -->
	<bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean>
	<!-- 代理类回调方法,也称为执行句柄,或者通知  -->
	<bean id="methodBefore" class="cn.aop.advice.DogAdvice"></bean>   
	<!-- 生成代理对象 -->
	<!-- 这是一个advice,也是一个advisor ,对所有方法增强增强,正常情况下  advisor = advice + pointCut -->
	<bean id="dogBeanFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 被代理类接口,可以没有,(如果接口使用cglib代理,如有有使用jdk动态代理,没有证实) -->
		<property name="proxyInterfaces" value="cn.aop.service.DogService"></property>
		<!-- 通知advisor -->
		<property name="interceptorNames" value="methodBefore"></property>
		<!--被代理的类  -->
		<property name="target" ref="dogService"></property>
	</bean>
</beans>

/**
	 * Spring AOP 最底层的AOP例子  ProxyFactoryBean代理Bean
	 */
	@Test
	public void test1(){
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");
		DogService dogService = context.getBean("dogBeanFactory", DogService.class);
		dogService.run();
		System.out.println(dogService.getClass());
	}

before.....
dog...run。。。。

class $Proxy4


使用ProxyFactoryBean代理目标类可选方法,正则匹配

package cn.aop.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * MethodInterceptor  环绕通知
 * @author zhzofx
 */
public class AroundDogAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
			System.out.println("方法前增强around。。。");
			Object obj = methodInvocation.proceed();
			System.out.println("方法后增强around。。。");
			return obj;
	}
}

<?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.xsd">
	 <!-- 被代理的类 -->
	<bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean>
	
	<!-- 代理类回调方法(环绕通知) -->
	<bean id="aroundDogAdvice" class="cn.aop.advice.AroundDogAdvice"></bean>	
	
	<!-- 这是一个advisor,带有切点的切面advisor -->
	<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="advice" ref="aroundDogAdvice"></property>
		<property name="patterns" value=".*run.*"></property>
	</bean>
	
	<bean id="regexpProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!--jdk 或者 CGlib 。你懂的,可有可无  -->
		<property name="proxyInterfaces" value="cn.aop.service.DogService"></property>
		<!-- 此处 是value,不是  ref  -->
		<property name="interceptorNames" value="regexpAdvisor"></property>
		<!-- 指向被代理类,需要将被代理类配置到这,繁琐。 -->
		<property name="target" ref="dogService"></property>
	</bean>
</beans>

/**
	 * 通过正则表达式对被代理类的方法进行增强,可以只对某些方法进行增强
	 */
	@Test
	public void test4(){
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");
		DogService dogService = context.getBean("regexpProxyFactoryBean", DogService.class);
		dogService.run();
	}

方法前增强around。。。
dog...run。。。。

方法后增强around。。。


使用BeanNameAutoProxyCreator根据正则匹配所有Bean加入AOP代理

/**
 * AfterReturningAdvice  后置通知
 * @author zhzofx
 *
 */
public class AfterAdvice implements AfterReturningAdvice{

	@Override
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("执行后增强。。。");
	}
}

<?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.xsd">
	 <!-- 被代理的类 -->
	<bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean>
	<bean id="catService" class="cn.aop.service.impl.CatServiceImpl"></bean>

	<!-- 通知 -->
	<bean id="afterAdvice" class="cn.aop.advice.AfterAdvice"></bean>
	
	<!-- 自动扫描代理bean , 对Bean的所有方法进行拦截
		 之前的做法都需要从ProxyFactory中获取对象,通过这种方式可以直接获取xml中配置的被代理bean,不现在必再从工厂中获取,
		 可以直接取dogService,返回的就是增强的代理类  -->
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<!-- 被拦截代理的bean , 拦截id 以Service结尾的Bean-->
		<property name="beanNames" value="*Service"></property>
		<!-- 通知 -->
		<property name="interceptorNames" value="afterAdvice"></property>
	</bean>
</beans>

	/**
	 * 自动扫描,对所有配置Bean都进行代理增强,不能精确到方法
	 */
	@Test
	public void test5(){
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");
		DogService dogService = context.getBean("dogService", DogService.class);
		dogService.run();
		CatService catService = context.getBean("catService", CatService.class);
		catService.run();
	}

dog...run。。。。
执行后增强。。。
cat,,run....
执行后增强。。。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值