public interface PersonDao {
public void savePerson();
}package com.itheima.spring.jdkproxy;
public class PersonDaoImpl implements PersonDao{
@Override
public void savePerson() {
System.out.println("save person");
}
}package com.itheima.spring.jdkproxy;
public class Transaction {
public void beginTransaction(){
System.out.println("begin transcation");
}
public void commit() {
System.out.println("commit");
}
}package com.itheima.spring.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 拦截器:
* 1、目标类导入进来
* 2、事务导入进来
* 3、invoke完成
* ①开启事务
* ②调用目标对象的方法
* ③事务提交
* @author xx
*
*/
public class MyInterceptor implements InvocationHandler{
private Object target; //目标类
private Transaction transaction;//事务,在这里代表一种功能,但如果要插入多个功能,就不能这么写了,看下一个案例,可以把他们加入在一个拦截器链表里
public MyInterceptor(Object target, Transaction transaction) {
super();
this.target = target;
this.transaction = transaction;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if("savePerson".equals(methodName) || "updatePerson".equals(methodName)
|| "deletePerson".equals(methodName)){
this.transaction.beginTransaction();//开启 事务
method.invoke(target);//调用目标方法
this.transaction.commit();//事务的提交
}else{
method.invoke(target);
}
return null;
}
}package com.itheima.spring.jdkproxy;
import java.lang.reflect.Proxy;
import org.junit.Test;
/**
* 1、拦截器的invoke方法是在是什么时候执行的?
* 当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法
* 2、代理对象的方法体的内容是什么?
* 拦截器的invoke方法的内容就是代理对象的方法的内容
* 3、拦截器中的invoke方法的参数method是谁在什么时候传递过来的?
* 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke
* 方法中的参数method就是代理对象调用的方法
* @author xx
*/
public class JDKProxyTest {
/**
* 1、创建一个目标类
* 2、创建一个事务
* 3、创建一个拦截器
* 4、动态生成一个代理对象
*/
@Test
public void test() {
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
MyInterceptor interceptor = new MyInterceptor(target,transaction);
/*
*1、目标类的加载器
*2、目标类的所有的接口
*3、拦截器
*/
PersonDao personDao = (PersonDao) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
personDao.savePerson();
}
}思考动态代理是怎么生成的? jdk的动态代理不用写代理方法,它是由java虚拟机实现的,因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的PersonDao接口,在实现PersonDao接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。
jdk动态代理比静态代理先进(不同)在哪?有什么优势?①解决代码重用的问题 ②解耦,代码灵活性高,调用目标代码时,会在方法“运行时”动态的加入
以上的JdkProxy代码有什么缺点?①拦截器中除了能调用目标对象的目标方法以外,功能是比较单一,这个例子只能处理事务(见下面代码) ②拦截器中invoke方法的if语句(切入点)是不靠谱的,因为一旦方法多了要写很多(可用正则表达式)
3、另一种改进的JDK动态代理模式package com.itheima.spring.jdkproxy;
/**
* 给日志、事务等做了一个抽象,而这个抽象就是Interceptor
* @author xx
*
*/
public interface Interceptor {
/*
* 除了目标对象的目标方法之外,其他任何的功能,比如事务、日志等都写在interceptor里面
*/
public void interceptor();
}package com.itheima.spring.jdkproxy;
/**
* Spring的实现比这复杂,用的责任链模式
* @author xx
*
*/
public class Transaction implements Interceptor{
@Override
public void interceptor() {
System.out.println("transaction");
}
}package com.itheima.spring.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
/**
* 拦截器:
* 1、目标类导入进来
* 2、事务导入进来
* 3、invoke完成
* ①开启事务
* ②调用目标对象的方法
* ③事务提交
* @author xx
*
*/
public class MyInterceptor implements InvocationHandler{
private Object target; //目标类
List<Interceptor> interceptors;
public MyInterceptor(Object target, List<Interceptor> interceptors) {
super();
this.target = target;
this.interceptors = interceptors;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if("savePerson".equals(methodName) || "updatePerson".equals(methodName)
|| "deletePerson".equals(methodName)){
for(Interceptor interceptor: interceptors){
interceptor.interceptor();
}
}
method.invoke(target);
return null;
}
}
package com.itheima.spring.jdkproxy;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
/**
* 1、拦截器的invoke方法是在是什么时候执行的?
* 当在客户端,代理对象调用方法的时候,进入到了拦截器的invoke方法
* 2、代理对象的方法体的内容是什么?
* 拦截器的invoke方法的内容就是代理对象的方法的内容
* 3、拦截器中的invoke方法的参数method是谁在什么时候传递过来的?
* 代理对象调用方法的时候,进入了拦截器中的invoke方法,所以invoke
* 方法中的参数method就是代理对象调用的方法
* @author xx
*/
public class JDKProxyTest {
/**
* 1、创建一个目标类
* 2、创建一个事务
* 3、创建一个拦截器
* 4、动态生成一个代理对象
*/
@Test
public void test() {
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
List<Interceptor> interceptors = new ArrayList<Interceptor>();
interceptors.add(transaction);
MyInterceptor interceptor = new MyInterceptor(target,interceptors);
/*
*1、目标类的加载器
*2、目标类的所有的接口
*3、拦截器
*/
PersonDao personDao = (PersonDao) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
personDao.savePerson();
}
}思考改进的代码解决了什么问题?解决了之前代码的缺点一的问题
新闻热点
疑难解答