學習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 ,配置文件的方式代理。

相關文章
相關標籤/搜索