博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
学习spring aop 和代理
阅读量:6572 次
发布时间:2019-06-24

本文共 7766 字,大约阅读时间需要 25 分钟。

hot3.png

本篇文章会详细的介绍AOP的实现过程。AOP的实现原理在上一篇博客中已经提到。

AOP面向切面的编程。他的主要实现是通过代理实现。网上有许多有关于代理的实现。我们一步一步来,从最简单到最复杂。

除了第一例子外。其他都是以  接口  目标类  代理类  mian函数的结构。

1.简单代理(结构图和代码)

classA代码

public class classA {	public void request() {		// TODO Auto-generated method stub		System.out.println("classA request");	}}

用来代理classA的代理类 proxyclassA

public class proxyclassA {	private classA classa;	String a;	public proxyclassA(classA classa) {		// TODO Auto-generated constructor stub		this.classa=classa;	}	public void request() {		// TODO Auto-generated method stub		System.out.println("执行request之前\n");		classa.request();		System.out.println("执行request之后\n");	}}

main类

public class main {	public static void main(String[] args) {		// TODO Auto-generated method stub		classA classa=new classA();		proxyclassA proxyclassa=new proxyclassA(classa);		proxyclassa.request();	}}

上面是一个“毫无用处”的代理。现实中很少代码会这么写。 但是aop 的编程思想在这里已经开始显现。

上面代理类最突出的一个问题是:每写一个类都需要建立一个代理类

2.我在上面基础上加上一个接口。如下(结构图和代码)

//接口public interface subjectj {	void  request();}//目标类public class classA implements subjectj{	public void request() {		// TODO Auto-generated method stub		System.out.println("classA request");	}}//代理类proxyclassApublic class proxyclassA implements subjectj{	private subjectj subjectj;	String a;	public proxyclassA(subjectj subjectj) {		// TODO Auto-generated constructor stub		this.subjectj=subjectj;	}	public void request() {		// TODO Auto-generated method stub		System.out.println("执行request之前\n");		subjectj.request();		System.out.println("执行request之后\n");	}}// mian 函数public class main {	public static void main(String[] args) {		classA classa=new classA();		subjectj proxyclassa=new proxyclassA(classa);		proxyclassa.request();	}}

以上就是静态代理,静态代理是不需要通过接口实现的。为了与动态代理比较才加上去接口。同时加上接口后我们发现,我们不需要为每一个目标类建立一个代理类。我们只需要保证代理类和目标类继承同一个接口。但是这样依然不够好。因为他们需要继承同一个接口,一旦接口多了,需要的代理类就会变多。

3.下面是动态代理。

//实现一个接口public interface isubject {	public void request();}//目标类,需要被代理的类public class Realsubject implements isubject {	@Override	public void request() {		// TODO Auto-generated method stub		System.out.println("realsubject request");	}}//实现代理的类import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class ProxySubject implements InvocationHandler{	private Object obj;	public ProxySubject() {		// TODO Auto-generated constructor stub	}	public ProxySubject(Object obj) {		this.obj=obj;	}	@Override	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {	    System.out.println( " before calling "  + method);	    method.invoke(obj,args);	    System.out.println( " after calling "  + method);		return null;	}	}//mian函数import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.lang.reflect.Constructor;import java.lang.reflect.Method;public class mainpro {	public static void main(String[] args) {		   Realsubject rs = new Realsubject(); // 在这里指定被代理类		   InvocationHandler ds = new ProxySubject(rs);		   Class cls = rs.getClass();		   // 以下是一次性生成代理		   isubject subject = (isubject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds );		   subject.request();	}}

动态代理真正实现了多个目标类一个代理类。但是代理类要做的规范很多。同时动态代理类需要实现接口,也难以实现代理多样化(同一个类中每个方法都有不同的代理)。

4.我们使用代理是为了实现aop编程。但上面依然不能解决我们编写代码的负重。尤其是上面的问题,为了解决问题,我决定引入spring。

首先,我们采用spring AOP 有两种方式。一种是常规JDK,一种是CGLIB。jdk就是我上面说的动态代理。CGLIB是另一种方式。这两种方式有什么区别?

1、如果目标类实现了接口,默认情况下会采用JDK的动态代理实现AOP

2、如果目标类实现了接口,可以强制使用CGLIB实现AOP
3、如果目标类没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

这样,我们就解决了一个问题。目标类不需要一定实现接口。

spring为我们提供编写代码的两种方式:注解,文件配置。无论是jdk还是CGLIB都可以用这两种方式实现。

看代码:

//接口public interface Aservice {	public void fooA(String _msg);}//目标类public class AseviceImpl implements Aservice{	public void fooA(String _msg) {		// TODO Auto-generated method stub		System.out.println(_msg);  	}    public void barA() {          System.out.println("AServiceImpl.barA()");      }  }//代理类,这里就不该叫他代理类了。应该是切面类import org.aspectj.lang.JoinPoint;  import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;  @Aspect  public class TestAspect {        //需要针对的方法   exexution 返回值   包.类 .方法(参数)    @Pointcut("execution(* sprigaop.AseviceImpl.*(..))")      private void pointCutMethod() {      }         //在该方法之后做什么    @After("pointCutMethod()")     public void doAfter(JoinPoint jp) {          System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }        //环绕该方法做什么    @Around("pointCutMethod()")    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {          long time = System.currentTimeMillis();          Object retVal = pjp.proceed();          time = System.currentTimeMillis() - time;          System.out.println("process time: " + time + " ms");          return retVal;      }      //在该方法之前做什么    @Before("pointCutMethod()")     public void doBefore(JoinPoint jp) {          System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }   }//mian主函数import org.springframework.beans.factory.BeanFactory;import org.springframework.context.support.ClassPathXmlApplicationContext;public class main {	public static void main(String[] args) {		// TODO Auto-generated method stub		BeanFactory b = new ClassPathXmlApplicationContext("spring.xml");        //注意有接口目标类。需要使用接口获取		Aservice as=(Aservice)b.getBean("aService");		as.fooA("hello");	}}

配置文件spring.xml

是不是很清晰。尤其是切面类(原来是代理类,真正的代理类已经隐藏了)中。针对哪一个函数方法。在此之前执行什么,在此之后执行什么。一目了然。使用注解的方式代理。只需要在配置文件中加入自动代理:<aop:aspectj-autoproxy />

那么上面是哪一种代理呢?答案是CGLIB,尽管这个类实现了接口。但我们在配置文件中将他强制使用了CGLIB。代码:proxy-target-class="true"

去掉proxy-target-class="true"后就是使用JDK来实现AOP

细节:有接口和无接口的代理,main里面获取是不一样的。有借口的使用接口获取目标对象,无接口使用类获取目标对象。

下一个例子代码:

//接口//目标类public class AseviceImpl {	public void fooA(String _msg) {		// TODO Auto-generated method stub		System.out.println(_msg);  	}    public void barA() {          System.out.println("AServiceImpl.barA()");      }  }//代理类import org.aspectj.lang.JoinPoint;  import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;  @Aspect  public class TestAspect {          public void doAfter(JoinPoint jp) {          System.out.println("log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }            public Object doAround(ProceedingJoinPoint pjp) throws Throwable {          long time = System.currentTimeMillis();          Object retVal = pjp.proceed();          time = System.currentTimeMillis() - time;          System.out.println("process time: " + time + " ms");          return retVal;      }          public void doBefore(JoinPoint jp) {          System.out.println("log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());      }   }//mian主函数import org.springframework.beans.factory.BeanFactory;import org.springframework.context.support.ClassPathXmlApplicationContext;public class main {	public static void main(String[] args) {		// TODO Auto-generated method stub		BeanFactory b = new ClassPathXmlApplicationContext("spring.xml");		AseviceImpl as=(AseviceImpl)b.getBean("aService");		as.fooA("hello");	}}

配置文件

这次是无接口,CGLIB ,配置文件的方式代理。

转载于:https://my.oschina.net/u/2259252/blog/889112

你可能感兴趣的文章
root用户重置其他密码
查看>>
C#------如何获取本机IP地址
查看>>
关于查询扩展版ESI高被引论文的说明
查看>>
【iCore3应用】基于iCore3双核心板的编码器应用实例
查看>>
Oracle推断值为非数字
查看>>
得知发行组长老潘今天岗位上最后一天就要离开有感
查看>>
[转]WF事件驱动(1)
查看>>
异常关闭MyEclipse 8.6后,不能重启
查看>>
多年前写的一个ASP.NET网站管理系统,到现在有些公司在用
查看>>
vue-cli中理不清的assetsSubDirectory 和 assetsPublicPath
查看>>
爆款 | Medium上6900个赞的AI学习路线图,让你快速上手机器学习
查看>>
Java基础知识梳理(五)从源码了解字符串
查看>>
从JDK源码角度看Short
查看>>
HTTP/2特性及其在实际应用中的表现
查看>>
解密Angular WebWorker Renderer (二)
查看>>
parceljs 中文文档24小时诞生记
查看>>
五年 Web 开发者 star 的 github 整理说明
查看>>
Docker 部署 SpringBoot 项目整合 Redis 镜像做访问计数Demo
查看>>
Android一种常见的布局困扰
查看>>
ReactNative字体大小不随系统字体大小变化而变化
查看>>