学习spring aop 和代理

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

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

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

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

classA代码ide

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类this

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 的编程思想在这里已经开始显现。spa

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

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

//接口
public interface subjectj {
	void  request();
}
//目标类
public class classA implements subjectj{

	public void request() {
		// TODO Auto-generated method stub
		System.out.println("classA request");
	}
}
//代理类proxyclassA
public 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是另外一种方式。这两种方式有什么区别?

一、若是目标类实现了接口,默认状况下会采用JDK的动态代理实现AOP
二、若是目标类实现了接口,能够强制使用CGLIB实现AOP
三、若是目标类没有实现了接口,必须采用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

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 

   <aop:aspectj-autoproxy proxy-target-class="true"/>
    <bean id="aspectBean" class="com.spring.service.TestAspect" />  
    <bean id="aService" class="sprigaop.AseviceImpl"></bean>  
</beans>

是否是很清晰。尤为是切面类(原来是代理类,真正的代理类已经隐藏了)中。针对哪个函数方法。在此以前执行什么,在此以后执行什么。一目了然。使用注解的方式代理。只须要在配置文件中加入自动代理:<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");
	}
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:tx="http://www.springframework.org/schema/tx"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"> 
    <aop:config>  
        <aop:aspect id="TestAspect" ref="aspectBean">  
            <!--配置com.spring.service包下全部类或接口的全部方法-->  
            <aop:pointcut id="businessService" expression="execution(* sprigaop.AseviceImpl.*(..))" />  
            <aop:before pointcut-ref="businessService" method="doBefore"/>  
            <aop:after pointcut-ref="businessService" method="doAfter"/>  
            <aop:around pointcut-ref="businessService" method="doAround"/>  
        </aop:aspect>  
    </aop:config> 
   
      
    <bean id="aspectBean" class="com.spring.service.TestAspect" />  
    <bean id="aService" class="sprigaop.AseviceImpl"></bean>  
</beans>

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

相关文章
相关标签/搜索