#动态代理Proxy
使用动态代理Proxy类的前提,要求被代理的类需要实现一个接口(JDK默认的动态代理) ##示例代码
-
1、定义一个接口PersonService
public interface PersonService { void save(String name); void update(String name,Integer personId); String getPersonName(Integer personId); }
-
2、定义一个类PersonServiceBean实现接口PersonService
public class PersonServiceBean implements PersonService{ private String user = null; public String getUser() { return user; } public PersonServiceBean() {} public PersonServiceBean(String user) { this.user = user; } @Override public void save(String name) { System.out.println("save方法"); } @Override public void update(String name, Integer personId) { System.out.println("update方法"); } @Override public String getPersonName(Integer personId) { System.out.println("getPersonName方法"); return "abinge"; } }
-
3、定义一个动态代理对象创建工厂类JDKProxyFactory
public class JDKProxyFactory implements InvocationHandler{ private Object targetObject; public Object createProxyInstance(Object targetObject){ this.targetObject = targetObject; /** * 参数1:目标代理对象的类加载器 * 参数2:目标代理对象的类实现的所有接口 * 参数3:InvocationHandler的实现类(需要实现invoke回调方法,在这里我们让该类JDKProxyFactory本身实现这个接口并重写invoke方法) * 返回值:即为目标对象的代理对象 */ return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), this); } /** * 在这个invoke方法中我们进行目标对象方法被调用前的拦截 * @param proxy 代理对象 * @param method 被拦截到的方法 * @param args 被拦截到的方法的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("invoke方法"); PersonServiceBean bean = (PersonServiceBean) this.targetObject; Object result = null; if(bean.getUser()!=null){ //将方法的调用委派给目标对象 result = method.invoke(targetObject, args); } return result; } }
-
4、编写测试代码
public class AOPTest { public static void main(String[] args){ JDKProxyFactory factory = new JDKProxyFactory(); //此时返回结果,需要使用目标对象实现的一个接口类型来接收 PersonService service = (PersonService) factory.createProxyInstance(new PersonServiceBean()); service.save("ac"); } }
上述测试代码执行的过程是:在调用save方法前会先调用invoke方法,然后通过invoke方法中的method.invoke(targetObject, args)代码去执行目标对象的save方法
#GClib动态代理
使用动态代理GClib,不要求被代理的类实现接口,需要导入GClib的jar包 ##示例代码
-
1、定义一个目标对象PersonService
public class PersonServiceBean{ private String user = null; public String getUser() { return user; } public PersonServiceBean() {} public PersonServiceBean(String user) { this.user = user; } public void save(String name) { System.out.println("save方法"); } public void update(String name, Integer personId) { System.out.println("update方法"); } public String getPersonName(Integer personId) { System.out.println("getPersonName方法"); return "abinge"; } }
-
2、定义一个动态代理对象创建工厂类GClibProxyFactory
public class GClibProxyFactory implements MethodInterceptor{ private Object targetObject; public Object createProxyInstance(Object targetObject){ this.targetObject = targetObject; Enhancer enhancer = new Enhancer(); //将targetObject指定为enhancer的父类,这样enhancer将覆盖targetObject中所有非final的方法 enhancer.setSuperclass(this.targetObject.getClass()); //为enhancer指定回调,参数为MethodInterceptor的实现类,需要重写intercept方法,也就是回调方法 //这里我们让该类GClibProxyFactory本身实现MethodInterceptor接口并重写intercept方法 enhancer.setCallback(this); return enhancer.create();//返回enhancer的实例 } /** * 在这个intercept方法中我们进行目标对象方法被调用前的拦截 * @param proxy 代理对象 * @param method 被拦截到的方法 * @param args 被拦截到的方法的参数 * @param methodProxy 代理方法 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("invoke方法"); PersonServiceBean bean = (PersonServiceBean) this.targetObject; Object result = null; if(bean.getUser()!=null){ //将方法的调用委派给目标对象 //这里使用第四个参数methodProxy来调用 result = methodProxy.invoke(targetObject, args); } return result; } }
-
4、编写测试代码
public class AOPTest { public static void main(String[] args){ GClibProxyFactory factory = new GClibProxyFactory(); //此时返回结果是目标对象的一个子类 PersonServiceBean service = (PersonServiceBean) factory.createProxyInstance(new PersonServiceBean()); service.save("ac"); } }
#由动态代理引出通知(环绕通知、前置通知、后置通知、例外通知、最终通知) 在动态代理的回调方法中我们可以在调用目标对象方法的前后不同位置添加如不同的业务逻辑,也就是所谓的“通知”,根据位置不同可添加不同的通知 ##示例代码
/**
* 在这个intercept方法中我们进行目标对象方法被调用前的拦截
* @param proxy 代理对象
* @param method 被拦截到的方法
* @param args 被拦截到的方法的参数
* @param methodProxy 代理方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//整个方法可以看作是一个环绕通知——>环绕通知
System.out.println("invoke方法");
PersonServiceBean bean = (PersonServiceBean) this.targetObject;
Object result = null;
if(bean.getUser()!=null){
//……advice()——>在这个位置可以添加——>前置通知
try{
//将方法的调用委派给目标对象
//这里使用第四个参数methodProxy来调用
result = methodProxy.invoke(targetObject, args);
//afteradvice()——>在这个位置可以添加——>后置通知
}catch(RuntimeException e){
//exceptionadvice()——>在这个位置可以添加——>例外通知
}finally{
//finallyadvice()——>在这个位置可以添加——>最终通知
}
}
return result;
}
}
#AOP概念 #Aspect(切面)
- 指横切性关注点的抽象即为切面,它与类相似,只是两者关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象。 #JoinPoint(连接点)
- 指那些被拦截的点,在Spring中,这些点指的是被拦截的目标对象的方法,因为Spring中只支持方法类型的连接点,实际上JoinPoint(连接点)还可以是field或类构造器。 #PoincCut(切入点)
- 指我们要对那些JoinPoint(连接点)进行拦截的定义。 #Advice(通知)
- 是指拦截到JoinPoint(连接点)之后,所要做的事情;通知分为:环绕通知、前置通知、后置通知、例外通知、最终通知。 #Target(目标对象)
- 需要被代理的目标对象。 #Weawe(织入)
- 指将Aspects(切面)应用到Target(目标对象)并导致Proxy对象创建的过程。 #Introduction(引入)
- 在不修改类代码的前提下,Introduction可以在运行期为类动态的添加一些方法或Feild。