切面(例如事务)
- 切面中的方法叫通知
- 客户端调用哪个方法,哪个方法就是连接点
- 只有符合切入点,才让通知和目标方法结合在一起
- 形成代理对象方法的过程就是织入
1.代理对象的方法=通知+目标方法
2.连接点就是目标接口中的一个方法
3.通知和目标方法是完全松耦合的
示例代码
-
事务
public class Transaction {
public void beginTransaction(){
System.out.println("begin transaction");
}
public void commit(){
System.out.println("commit");
}
}
-
共同接口(目标类和代理类实现相同的接口)
public interface PersonDao {
public void savePerson();
}
-
目标类
public class PersonDaoImpl implements PersonDao{
public void savePerson() {
System.out.println("save person");
}
}
-
拦截器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 1、引入personDao和Transaction
* 2、完成invoke方法
*/
public class MyInterceptor implements InvocationHandler{
private Object target;
private Transaction transaction;
public MyInterceptor(Object target,Transaction transaction){
this.target = target;
this.transaction = transaction;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equals("savePerson")
||method.getName().equals("updatePerson")){
this.transaction.beginTransaction();
method.invoke(this.target, args);//调用目标类的目标方法
this.transaction.commit();
}else{
method.invoke(this.target, args);//调用目标类的目标方法
}
return null;
}
}
-
测试
import java.lang.reflect.Proxy;
import org.junit.Test;
/*
*
* 问题:
* 1、拦截器中的invoke方法在什么时候被调用的
* 在代理对象调用方法的时候,进入了拦截器中的invoke方法
* 2、拦截器中的method参数是什么?在什么时候由实参传递给形参的
* 代理对象的方法的名称是什么,method参数就是什么
* 代理对象调用方法的时候,进入了拦截器中的invoke方法,这个时候,传递参数
* 3、生成的代理对象实现了接口,代理对象的方法体的内容是什么?
* 方法体的内容就是拦截器中的invoke方法体的内容
*/
/**
* jdkproxy的优点
* 动态的产生代理对象,所以只需要用一个拦截器就可以了
* jdkproxy的缺点
* 如果在invoke方法中做事务的判断,将是一件很复杂的事情
* 程序员还是写拦截器了,写拦截器中的invoke方法了,所以invoke方法还需要修改
*
* 说明:
* 目标类和代理类实现了共同的接口
*
*/
public class ProxyTest {
@Test
public void testProxy(){
PersonDao target = new PersonDaoImpl();
Transaction transaction = new Transaction();
MyInterceptor interceptor = new MyInterceptor(target, transaction);
/**
* 第一个参数 目标类的类加载器
* 第二个参数 目标类实现的所有的接口
* 第三个参数 拦截器
*/
PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
personDao.savePerson();
}
}