Spring AOP编程(二)-AOP实现的三种方式

AOP的实现有三种方式:

l         aop底层将采用代理机制进行实现。

l         接口 + 实现类 :spring采用 jdk 的动态代理Proxy。

l         实现类:spring 采用 cglib字节码增强。

一.手工方式

1.JDK动态代理

JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口

1.目标类:接口 + 实现类

2.切面类:用于存通知 MyAspect

3.工厂类:编写工厂生成代理

4.测试

1.目标类

UserService.java

package com.zk.a_jdk;

public interface UserService {
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy deleteUser");
	}

}

2.切面类

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {
	
	public void before(){
		System.out.println("鸡头");
	}
	
	public void after(){
		System.out.println("牛后");
	}
}

3.工厂

package com.zk.a_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanFactory {
	//手工代理
	public static UserService createService(){
		//1.目标类
		final UserService userservice=new UserServiceImpl();
		//2.切面类
		final MyAspect myAspect=new MyAspect();
		//3.代理类:将目标类(切入点)和切面类(通知)结合-->切面
		//Proxy.newProxyInstance
		/*
		 * 参数一:loader类加载器,动态代理类,运行时创建,任何类都需要类加载器将其加载至内存。
		 * 一般情况下:当前类,class.getClassLoader();
		 * 目标类实例:getClass().get...
		 * 参数二:interfaces,代理类需要实现的所有接口
		 * 方式一:目标类实例.getClass().getInterfaces();注意:只能获得自己的接口,获得不到父元素的接口
		 * 方式二:new Class[]{UserService.class}
		 * 例如:jdbc驱动
		 * 参数三:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部类
		 * 提供invoke方法,代理类每一个方法执行时,都将去调用invoke
		 * 参数三.1.Object proxy代理对象
		 * 参数三.2.Method method 代理对象当前方法的描述对象(反射)
		 * 执行方法方法名:method.getName();
		 * 执行方法:method.invoke(对象,实际参数)
		 * 参数三.3 Object[] args 方法实际参数
		 */
		UserService proxyService=(UserService)Proxy.newProxyInstance
				(MyBeanFactory.class.getClassLoader(), 
						userservice.getClass().getInterfaces(), new InvocationHandler(){

							@Override
							public Object invoke(Object proxy, Method method,
									Object[] args) throws Throwable {
								// TODO Auto-generated method stub
								
								//前执行
								myAspect.before();
								//执行目标类的方法
								Object obj=method.invoke(userservice, args);
								
								//后执行
								myAspect.after();
								
								return null;
							}
				});
		return proxyService;
	}
}

4.测试类

package com.zk.a_jdk;

import org.junit.Test;

public class TestJDK {

	@Test
	public void test(){
		UserService userservice=MyBeanFactory.createService();
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

运行效果:

2.  CGLIB字节码增强

l         没有接口,只有实现类。

l         采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

l         导入jar包:

1.目标类

UserService.java

package com.zk.a_jdk;

public interface UserService {
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy deleteUser");
	}

}

2.切面类

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {
	
	public void before(){
		System.out.println("鸡头");
	}
	
	public void after(){
		System.out.println("牛后");
	}
}

3.MyBeanFactory.java工厂类

package com.zk.b_cglib;


import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;


public class MyBeanFactory {
	//手工代理
	public static UserService createService(){
		//1.目标类
		final UserServiceImpl userservice=new UserServiceImpl();
		//2.切面类
		final MyAspect myAspect=new MyAspect();
		/*3.代理类
		 * 采用字节码增强框架-cglib,程序运行时创建目标类的子类,从而对目标类进行增强
		 * 导入jar包
		 * intercept等效于jdk中invoke方法
		 * 参数一二三 与invoke相同
		 * 参数四方法的代理
		 */
		Enhancer enhance=new Enhancer();
		//确定父类
		enhance.setSuperclass(userservice.getClass());
		enhance.setCallback(new MethodInterceptor(){
			//设置回调函数,MethodInterceptor接口等效 jdk InvocationHandler接口
			@Override
			public Object intercept(Object proxy, Method method, Object[] args,
					MethodProxy methodproxy) throws Throwable {
				// TODO Auto-generated method stub
				//前before
				myAspect.before();
				//执行目标类的方法
				Object obj=method.invoke(userservice, args);
				//执行代理类的父类
				methodproxy.invokeSuper(proxy, args);
				//后after
				myAspect.after();
				return null;
			}

			
		});
		//创建代理
		UserServiceImpl proxyservice=(UserServiceImpl) enhance.create();
		return proxyservice;
	}
}

 4.TestCglib.java测试

package com.zk.b_cglib;

import org.junit.Test;

public class Testcglib {

	@Test
	public void test(){
		UserService userservice=MyBeanFactory.createService();
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

运行效果图:

二.半自动方式

让spring 创建代理对象,从spring容器中手动的获取代理对象。

导入jar包:

AOP:AOP联盟(规范)、spring-aop (实现)

1.目标类

UserService.java

public interface UserService {	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("deleteUser");
	}

}

2.切面类

/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		
		//手动执行目标方法
		Object obj = mi.proceed();
		
		System.out.println("后3");
		return obj;
	}
}

3.spring配置

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    <!-- 创建目标类 -->
    <bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean>
    
    <!-- 创建切面类 -->
    <bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean>
    
    <!-- 创建代理类
                 使用工厂bean factorybean,底层调用getObject(), 返回特殊bean
      ProxyBeanFactory用于创建代理工厂bean,生成特殊代理对象
      interface确定接口
                  通过Array确定多个值
                  只有一个值时,value=""
      target确定目标类
      interceptorNames:通知切面类名称,类型String[],如果设置一个值, value=""
      optimize:强制使用cglib
      <property name="optimized value="true"></property>
      底层机制:
      如果目标类有接口,采用jdk代理
      如果没有接口,采用cglib代理
      如果声明式optimize=true,都使用cglib
     -->
    <bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interfaces" value="com.zk.factorybean.UserService"></property>
    <property name="target" ref="userserviceid"></property>
    <property name="interceptorNames" value="aspectid"></property>
    </bean>
</beans>

  

4.Testfactorybean.java

package com.zk.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Testfactorybean {

	@Test
	public void test(){
		String path="com/zk/factorybean/ApplicationContext.xml";
		ApplicationContext ac=new ClassPathXmlApplicationContext(path);
		UserService userservice=(UserService) ac.getBean("proxyServiceid");
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

  

运行效果:

三.spring aop编程:全自动

从spring容器获得目标类,如果配置aop,spring将自动生成代理。

要确定目标类,aspectj 切入点表达式,导入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

 

1.目标类

UserService.java

public interface UserService {	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("deleteUser");
	}

}

2.切面类

/**
 * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
 * * 采用“环绕通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		
		//手动执行目标方法
		Object obj = mi.proceed();
		
		System.out.println("后3");
		return obj;
	}
}

3.spring配置

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    ">
    <!-- 创建目标类 -->
    <bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean>
    
    <!-- 创建切面类 -->
    <bean id="aspectid" class="com.zk.springAop.MyAspect"></bean>
    
    <!-- Aop编程
    1.导入命名空间
    2.使用<aop:config>进行配置
    proxy-target-class="true"声明是使用cglib代理
    <aop:pointcut>:切入点,从目标对象上获取具体的方法
    <aop:advisor>特殊的切面,只有一个通知和一个切入点
    advise-ref 通知引用
    pointcut-ref 切入点引用
    advisor通知
    3.切入点表达式
    execution(* com.zk.springAop.*.*(..))
    选择方法 *表示返回值任意    包                                      类名任意. 方法名任意 . 参数任意 .
        -->
    <aop:config>
    <aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/>
    <aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/>
    </aop:config> 
</beans>

  

猜你喜欢

转载自www.cnblogs.com/longlyseul/p/10017027.html