springエッセイ(二)OP


AOP(Asppect-Oriented Programming)面向けプログラミング)
aop(Asppect-Oriented Prograamming)とは、切断面に向けてプログラミングし、対象に向けてプログラミングする一種の補足である.aopはプログラムの運行角度からプログラムの流れを考慮して、業務処理過程のうどんを抽出します.
1,AOPにおける概念
Asppect(うどん):          通知(Advice)と切り込み点(Pointcut)の結合であり、通知と切り込み点は、うどんに関するすべての内容を共同で定義しました.
Advice(通知):          通知とは、joinpointをブロックした後にすることを通知といいます.通知は事前通知、後置通知、異常通知、最終通知に分かれています.折り返し通知(切断したい機能は、「いつ」と「何をする」と定義されていますか?)
Pointcut(切り込みポイント):    切込みポイントとは、私たちがそれらをブロックするという定義です.   切り込み点は「何処」と定義されています.
JoinPoint(接続点):接続点とは、それらがブロックされている点のことです.springでは、これらの点は方法の種類の接続点のみをサポートするため、方法を指す.
ターゲット:   代理のターゲット
Weaving(織り込み):       は、新しいプロキシオブジェクトを作成するために、切面をターゲットオブジェクトに適用するプロセスです.
Introduction(導入):  クラスコードを修正しない前提で、Introductionは、クラスのために動的にいくつかの方法またはFieldを実行期間に追加することができる.
AOP代理:springAOP作成の代理対象.目標対象の強化とも言える.springにおけるエージェントは、jdkの動的エージェントであっても良いし、CGLOIBエージェントであっても良い.前者はインターフェースを実現するオブジェクトのためのプロキシであり、後者はインターフェースを実装しないオブジェクトのためのプロキシである.springは、特定のクラスにインターフェースがあるかどうかによって、プロキシプロセスを異なる方法で処理します.
2,spring中の2つのエージェント(内部実装)
1,JDKのダイナミックエージェント
JDKのダイナミックエージェントの主な核心方法は、java.lang.reflect.Proxy類のpublic static Objectです. newProxyInstance(Class Loader loader、 Class[]interfaces,InvocationHandler h)  この方法は、throws IllagalAgMentExceptionです.
パラメータ:loader-プロキシクラスを定義する種類のキャリア   、インターフェースリスト、h-メソッド呼び出しの呼び出し処理プログラムを割り当てます.
その中のInvocationHandlerはjava.lang.reflectの下のインターフェースです.
は、指定されたクラスのキャリアによって定義され、指定されたインターフェースを実現するプロキシクラスの指定された呼び出し処理プログラムのプロキシ例を返します.
InvocationHandlerインターフェースは一つの方法しかないです.Object invoke(Object proxy,Method,Object[]args) throws Throwable
プロキシの例では、方法を呼び出して結果を返します.方法に関連するプロキシの例で方法を呼び出すと、この方法は、処理プログラムを呼び出して呼び出されます.
次のようにCusstmerServiceの保存更新操作に事務処理を加えます.
ICustomeServiceインターフェース:
package com.xiaohui.proxy;
public interface ICustomeService {
	void save(Customer c);
	void update(Customer c);
}
Custoomer ServiceImpl Cusstomer ServiceImpl類
package com.xiaohui.proxy;
public class CustomerServiceImpl implements ICustomeService{
	public void save(Customer customer) {
		System.out.println("CustomerServiceImpl......save..."+customer.getName());
	}
	public void update(Customer c) {
		System.out.println("CustomerServiceImpl......update..."+c.getName());
	}
}
MyInvocationHandler Factory MyInvocationHandler Factory類
package com.xiaohui.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandlerFactory implements InvocationHandler {
	//    
	private Object target;
	/**
	 *      
	 * @param target
	 * @return     
	 */
	public Object getProxyInstance(Object target){
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//proxy      
		//         
		System.out.println("session.beginTranscation()");
		//              filter  chain.doFilter(request,response);
		Object obj = method.invoke(target, args);
		//         
		System.out.println("session.getTranscation().commit()");
		return obj;
	}
}
テストクラス:
	@Test
	public void testProxy() throws Exception {
		ICustomeService service = new CustomerServiceImpl();
		Customer customer = new Customer();
		customer.setName("  ");
		MyInvocationHandlerFactory factory = new MyInvocationHandlerFactory();
		ICustomeService serviceProxy =(ICustomeService) factory.getProxyInstance(service);
		serviceProxy.save(customer);
		System.out.println("-------------------------------");
		serviceProxy.update(customer);
	}
 印刷結果:
session.begintTranscation()CustoomerServiceImpl...save...張珊session.get Transcation().comit()--------------------session.begintTranscation()CusomerServiceImpl...udate...張珊...
2,CGLOIBエージェントを使用する
Springを使用するCGLOIBエージェントの中で主に使用されるクラスは、net.sf.cglib.proxy.Enhancerです.その核心方法は:Object hancer.creat()である.
コードは以下の通りです
MyCallbackFactory類は、このような実現インターフェースとJDKが実現するインターフェースの名前が全く同じであり、インターフェースの構造も一致しており、単独のspringがそれに対して別の調整をしていることに注意が必要である.だから、開発者たちは間違ったインターフェースを実現できません.
package com.xiaohui.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
public class MyCallbackFactory implements  InvocationHandler {
	private Object target;
	public Object getInstance(Object target){
		this.target = target;
		Enhancer hancer = new Enhancer(); 
		hancer.setClassLoader(target.getClass().getClassLoader());
		hancer.setSuperclass(target.getClass());
		hancer.setCallback(this);
		return hancer.create();
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("your before logic progream.....");
		Object obj =  method.invoke(target, args);
		System.out.println("your after logic progream.....");
		return obj;
	}
}
テストクラス:
@Test
	public void testProxy2() throws Exception {
		CustomerServiceImpl service = new CustomerServiceImpl();
		Customer customer = new Customer();
		customer.setName("  ");
		MyCallbackFactory factory = new MyCallbackFactory();
		CustomerServiceImpl proxy =  (CustomerServiceImpl) factory.getInstance(service);
		proxy.update(customer);
		System.out.println(proxy.getClass().getSuperclass().getName());
	}
印刷結果:
your before logic progream....CustoomerServiceImpl...udate...张珊your after logic progream....comp.xiahui.proxyCustomerviceImplは、この代理人が真実の対象となるサブクラスを示しています.エージェントが必要なオブジェクトはインターフェースを実装しなくてもかまわないです.CGLOIBにエージェントされてもいいです.
3,org.aopalliance.intercept.MethodInterceptorインターフェースを実現することによって、springのorg.spring frame ewark.aop.frame ebook.ProxyFactoryBen類の配置xmlを使用して代理を取得します.内部メカニズムは上の2種類です.
Transcation Interceptorクラス:
package com.xiaohui.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class TranscationInterceptor implements MethodInterceptor {
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("your Transcation...logic progream...Before....");
		Object obj = invocation.proceed();
		System.out.println("your Transcation...logic progream...After....");
		return obj;
	}
}
ICustomeServiceインターフェース:
package com.xiaohui.aop;
public interface ICustomeService {
	void save(Customer c);
	void update(Customer c);
}
Custoomer ServiceImpl類:
package com.xiaohui.aop;
public class CustomerServiceImpl implements ICustomeService{
	public void save(Customer customer) {
		System.out.println("CustomerServiceImpl......save..."+customer.getName());
	}
	public void update(Customer c) {
		System.out.println("CustomerServiceImpl......update..."+c.getName());
	}
}
appication Contect.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<bean id="transcationInteceptor" class="com.xiaohui.aop.TranscationInterceptor" />
	<bean id="customerService" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="proxyInterfaces" value="com.xiaohui.aop.ICustomeService" />
		<property name="target">
			<bean class="com.xiaohui.aop.CustomerServiceImpl"/>
		</property>
		<property name="interceptorNames">
			<list>
				<value>transcationInteceptor</value>
			</list>
		</property>
	</bean>
</beans>
このようなスペックを使うと、プロキシされているクラスは、インターフェースが実現されていないならProxyFactoryBeanにを配合しなくてもいいです.インターフェースがあるのはJDKダイナミックエージェントによって作成されます.テストコード:
@Test
	public void testProxy2() throws Exception {
		Customer customer = new Customer();
		customer.setName("  ");
		ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
		ICustomeService service = ctx.getBean("customerService",ICustomeService.class);
		service.save(customer);
	}
印刷結果:
your Transcation...logic progream...Before...CustoomerServiceImpl...save...张珊your Transcation...logic progream...After...
3、springは@AsppectJでAOP機能を注釈して追加します.
AsppectJはJava AOPプログラミングに特化したJava拡張言語です.Springでは@AsppectJコメントを使ってAOP機能を追加することができます.
@AsppectJコメントを使ってプログラミングするには、まずSpringのプロファイルにaop名前空間を導入します. ラベル
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
        <aop:aspectj-autoproxy/>
</beans>
@AsppectJ注釈を使用して、プロキシを取得するには、まず一つの断面を定義する必要がある.(クラスを定義し、@Asppect声明を使用する)
 
下記のカット類TransCationService:
package com.xiaohui.aop;

import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TransCationService {

	@Pointcut("execution(* com.xiaohui.aop.*ServiceImpl.*(..))")
	public void pointcut() {
	}

	@Before("pointcut()")
	public void beginTranscation(JoinPoint jp) {
		System.out.println("   :" + jp.getTarget().getClass().getName());
		System.out.println("  : " + Arrays.toString(jp.getArgs()));
		System.out.println("  : " + jp.getSignature().getName());
		System.out.println("session.brgintranscation()........");
	}

	@AfterReturning("pointcut()")
	public void commit() {
		System.out.println("session.getTranscation().commit()");
	}

	@AfterThrowing(pointcut = ("execution(* com.xiaohui.aop.*ServiceImpl.*(..))"), throwing = "e")
	public void rollback(Throwable e) {
		System.out.println("    ......" + e.getMessage());
		System.out.println("session.rollback....");
	}

	@After("pointcut()")
	public void closeSession() {
		System.out.println("session.close()");
	}
}
上の
@Pointcut("execution(* com.xiaohui.aop.*ServiceImpl.*(..))")
	public void pointcut(){}
この切込み点式を定義しています.最初の‘*’は戻り値を任意のタイプとし、第二の‘*’はcomp.xiahui.aopの下にServiceImplで終わるクラスを表し、第三の‘*’はすべての方法()を表します.任意のパラメータ類表を表します.最終的には、comp.xiaohui.aopパッケージの下で値が任意のタイプに戻り、クラス名がServiceImplで終わるパラメータクラスはすべての方法を制限しないという意味です.
 
@Before(「pointcut()」:事前通知は、ターゲットエージェントの実行方法の前に呼び出します.上記で定義されている切り込み点、使用方法名を直接引用します.
@AfterReturning(「pointcut()」:バック通知は、ターゲットエージェントがメソッドを成功裏に実行した後に呼び出す.
@After(「pointcut()」:最終通知は、ターゲットエージェントがメソッドを実行した後、ターゲットメソッドが成功したかどうかにかかわらず実行されます.
@After Throwing(.))、throwing=「e」:異常通知:一つの方法で例外を投げて実行する.throwingは、投げ出す異常を表します.その切り込みポイントは、自分で再定義した切り込みポイント表現です.
 
appication Contect.xmlの構成は以下の通りです.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
	
	<bean  id="advice" class="com.xiaohui.aop.TransCationService"/>
	<bean id="customerService" class="com.xiaohui.aop.CustomerServiceImpl"/>
	<aop:aspectj-autoproxy/>
</beans>
ICustomerServiceインターフェースとテストクラスと2.3のコードが一致しています.異常がある場合をテストするために、CustomerviceImpl類のsave方法を少しずつ修正します.saveの方法は以下の通りです
public void save(Customer customer) {
		System.out.println("CustomerServiceImpl......save..."+customer.getName());
		if(new Random().nextInt(10)>5){
			throw new RuntimeException("    .....");
		}
	}
これにより、例外を出すことができます.異常のない印刷結果は以下の通りです.
ターゲットクラス:comp.xiaohui.aop.customerviceImplパラメータ:[comp.xiahui.aop.Customer@1700391」方法:save session.bragistranscation()….CustoomerServiceImpl...save...張珊session.get Transcation().commt()session.close()
異常に投げられた印刷結果は以下の通りです.(テスト中に最終通知の方法が異常通知の方法に定義されていたら、session.closeを印刷してからsession.rollbackを印刷します.ちょっと分かりません.)
目標種類:comp.xiaohui.aop.customerviceImpl
パラメータ:[comp.xiahui.aop.Customer@118223d」
方法:セーブ
session.brigistration()….
CustoomerServiceImpl…save…張珊
異常が発生しました.保存に失敗しました.
session.rollback…
session.close()
 これらの通知のほかに、もう一つの折り返し通知があります.@Around("execution(*.xiahui.aop.*ServiceImpl.*)")
 
TransCationServiceうどん類:
package com.xiaohui.aop;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class TransCationService {
	public void pointcut() {
	}

	public void beginTranscation(JoinPoint jp) {
		System.out.println("   :" + jp.getTarget().getClass().getName());
		System.out.println("  : " + Arrays.toString(jp.getArgs()));
		System.out.println("  : " + jp.getSignature().getName());
		System.out.println("session.brgintranscation()........");
	}

	public void commit() {
		System.out.println("session.getTranscation().commit()");
	}

	public void closeSession() {
		System.out.println("session.close()");
	}

	public void rollback(Throwable e) {
		System.out.println("    ......" + e.getMessage());
		System.out.println("session.rollback....");
	}

	@Around("execution(* com.xiaohui.aop.*ServiceImpl.*(..))")
	public Object around(ProceedingJoinPoint point) {
		this.beginTranscation(point);
		try {
			Object obj = point.proceed();
			this.commit();
			return obj;
		} catch (Throwable t) {
			this.rollback(t);
		} finally {
			this.closeSession();
		}
		return null;
	}
}
 テストの結果は上のテストの結果と一致します.
4,appication Contect.xmlではaop名前空間プロファイルエージェントを使用します.
xmlにもaopの名前空間を導入する必要があります.今回は開けなくてもいいです.
同様に、注釈を使用して、うどん類とadvice声明方法を声明する必要もない.
xmlの構成は以下の通りです
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

	<aop:config>
		<aop:pointcut expression="execution(* com.xiaohui.aop.*ServiceImpl.*(..))" id="ponit"/>
		<!--      -->
		<aop:aspect ref="advice">
			<aop:before method="beginTranscation" pointcut-ref="ponit"/>
			<aop:after-throwing method="rollback" pointcut-ref="ponit" throwing="e"/>
			<aop:after-returning method="commit" pointcut-ref="ponit"/>
			<aop:after method="closeSession" pointcut-ref="ponit"/>
		</aop:aspect>
	</aop:config>
	<!--        -->
	<bean  id="advice" class="com.xiaohui.aop.TransCationService"/>
	<!--          -->
	<bean id="customerService" class="com.xiaohui.aop.CustomerServiceImpl"/>
</beans>
テストコードとICustomerServiceインターフェース及びCustomerServiceImpl類は全部3の中と同じです.TransCationServiceについては、注釈の有無は大丈夫です.xmlではが開いていないので、テストに影響しません.
テスト結果も上記3と一致しました.同じ問題があったらxmlにを設定します. aop:afterの後に印刷結果の順序と配置の順序が一致していますので、分かりません. beforeはどこにいても先に実行して大丈夫です.