引言
大家都知道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....
执行后增强。。。