zoukankan      html  css  js  c++  java
  • 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-dependenciesorg.aspectjcom.springsource.org.aspectj.weaver1.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>
    

      

  • 相关阅读:
    jemeter使用笔记
    webtest mobile + Android / Battery Historian / SoloPi
    script / go / golang
    my live house / air conditioning / dajin / dakin / FTXG50JV2CW
    OS + Centos OS 8 Thinkpad TrackPoint
    network router Gpon
    Mybatisplus 自定义sql 使用条件构造器 多表查询分页
    处理fastJson 序列化时间问题
    js 实现轮播图 超级简单 组件已封装
    Webpack-dev-server的proxy用法
  • 原文地址:https://www.cnblogs.com/longlyseul/p/10017027.html
Copyright © 2011-2022 走看看