加入通知的地点可以为:方法调用,异常抛出,要修改的字段。spring采用方法调用,有四种加入通知的方式:前置通知,后置通知,环绕通知,异常通知,通知也有两种代理方式,①jdk的动态代理,即接口代理②对类代理,即cglib代理。推荐①,耦合性低,且使用②的话,要考虑final修饰的方法不能被代理,因为不能被重写,无法织入通知。
具体专有名词不够清楚,可以看:
https://blog.csdn.net/haidaoxianzi/article/details/79778324
对目标对象,通知,代理的关系,可以理解为如下图示:
以下为体验aop,通过接口代理的前置通知demo。
1 定义接口,目标对象,以及前置通知
①前置通知
package cn.dbe.spring.aop.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println("into MyMethodBeforeAdvice");
}
}
②接口1,2
package cn.dbe.spring.aop.service;
public interface WelcomeService {
void sayName(String a);
}
package cn.dbe.spring.aop.service;
public interface WelcomeService2 {
void sayName2(String b);
}
③目标对象
package cn.dbet.spring.aop.service.impl;
import cn.dbe.spring.aop.service.WelcomeService;
import cn.dbe.spring.aop.service.WelcomeService2;
public class WelcomeServiceImpl implements WelcomeService, WelcomeService2 {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sayName(String a) {
System.out.println(a + "+" + name);
}
@Override
public void sayName2(String b) {
System.out.println(b + "+" + name);
}
}
2 在配置文件中通过代理工厂bean定义代理对象,属性来配置通过哪个“接口”来代理,从而对“目标对象” 织入 “通知”。
<?xml version="1.0"?>
<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-3.0.xsd">
<!-- 目标对象 -->
<bean id="welcomeServiceTarget" class="cn.dbet.spring.aop.service.impl.WelcomeServiceImpl">
<property name="name" value="123wq"/>
</bean>
<!-- 前置通知 -->
<bean id="myMethodBeforeAdvice" class="cn.dbe.spring.aop.advice.MyMethodBeforeAdvice"/>
<!-- 代理 -->
<bean id="welcomeService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 拦截器名集 -->
<property name="interceptorNames">
<list>
<value>myMethodBeforeAdvice</value>
</list>
</property>
<!-- 代理接口集合 ,接口代理-->
<property name="proxyInterfaces">
<list>
<value>cn.dbe.spring.aop.service.WelcomeService</value>
<value>cn.dbe.spring.aop.service.WelcomeService2</value>
</list>
</property>
<!-- 目标对象 -->
<property name="target" ref="welcomeServiceTarget"/>
<!-- 代理目标类,对类代理(cglib代理),需要引入第三方依赖类库 -->
<property name="proxyTargetClass" value="true"/>
</bean>
</beans>
3 test
package cn.dbet.spring.aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.dbe.spring.aop.service.WelcomeService;
public class App {
public void testService() {
ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml", App.class);
//接口代理
System.out.println("--接口代理start");
WelcomeService w = (WelcomeService) ac.getBean("welcomeService");
w.sayName("a");
WelcomeService2 w2 = (WelcomeService2) w;//(WelcomeService2) ac.getBean("welcomeService");
w2.sayName2("b");
WelcomeServiceImpl w3 = (WelcomeServiceImpl) ac.getBean("welcomeServiceTarget");
System.out.println("--普通的调用类的方法,不会加入通知 start--");
w3.sayName("c");
w3.sayName2("c");
//对类代理 ,cglib代理,原理:通过继承代理对象实现对类代理
WelcomeServiceImpl w4 = (WelcomeServiceImpl) w;
System.out.println("--对类代理");
w4.sayName("d");
w4.sayName2("d");
}
}
输出结果为:
--接口代理start
into MyMethodBeforeAdvice
a+123wq
into MyMethodBeforeAdvice
b+123wq
--普通的调用类的方法,不会加入通知 start--
c+123wq
c+123wq
--对类代理
into MyMethodBeforeAdvice
d+123wq
into MyMethodBeforeAdvice
d+123wq