浅谈Spring之AOP篇

  •  什么是代理模式

代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

举个例子来说明:假如说我现在想要办一个婚礼,虽然我还要去找酒店,还要去布置现场,还要去找婚车等,但是这确实太浪费时间和精力了。我只是想愉快轻松的结个婚,为什么我还要额外做这么多事呢?于是我就通过婚庆公司来帮我们订酒店、布置现场、,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。用图表示如下:

  • 静态代理 

测试环境搭建:

1.编写一个共同的接口Marry

public interface Marry {
	void Marry();
}

2.编写要结婚的新人Couple.java

public class Couple implements Marry{

	@Override
	public void Marry() {
		System.out.println("结婚的人入场");
	}
	
}

        3.编写婚庆公司类WeddingServices.java

public class WeddingServices implements Marry {
	Couple couple;

    public WeddingServices(Couple couple) {
		super();
		this.couple = couple;
	}

	@Override
	public void Marry() {
		System.out.println("婚庆公司:");
		System.out.println("找酒店和婚车");
		System.out.println("布置现场");
		couple.Marry();
		System.out.println("收拾现场,婚礼结束");
	}

}

        4.编写代理测试类testProxy.java

public class testProxy {
	public static void main(String[] args) {
		WeddingServices weddingServices = new WeddingServices(new Couple());
		weddingServices.Marry();
	}
}

  • JDK动态代理

        什么是JDK动态代理?

使用jdk的反射机制,创建对象的能力, 创建的是代理类的对象。 而不用你创建类文件。不用写java文件。动态:在程序执行时,调用jdk提供的方法才能创建代理类的对象。JDK动态代理,必须有接口,目标类必须实现接口, 没有接口时,需要使用CGLIB动态代理

哈哈,我们废话不多说,我们直接上代码

        1.我们还是以结婚为例子来讲解,我们先建一个共同的结婚接口

public interface Marry {
	void Marry();
}

        2.然后再建一个结婚对象Couple类

public class Couple implements Marry{
	
	@Override
	public void Marry() {
		System.out.println("结婚的人入场");
	}
	
}

·        3.最后我们建立JDK动态代理类DynamicProxy.java

public class DynamicProxy{
	private Object target;
	public DynamicProxy(Object target) {
		super();
		this.target = target;
	}
	//通过Proxy.newProxyInstance获取代理对象
	public Object getProxy() {
		//获取类加载器
		ClassLoader classLoader = this.getClass().getClassLoader();
		//得到目标对象的实现数组
		Class[] interfaces = target.getClass().getInterfaces();
		//获取InvocationHandler接口
		InvocationHandler invocationHandler  = new InvocationHandler() {
			/** 
			 * proxy代表实例
			 * method表示目标对象的方法,可以通过getmethod来获取
			 * args表示参数
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				//调用目标对象中的方法
				method.invoke(target, args);
				return null;
			}
			
		};
		Object proxy = Proxy.newProxyInstance(classLoader,interfaces, invocationHandler);
		return proxy;
	} 

}

        4.最后一步我们来写一个测试类testDynaminProxy

public class testDynaminProxy {
	public static void main(String[] args) {
		DynamicProxy proxy = new DynamicProxy(new Couple());
		Marry couple = (Marry) proxy.getProxy();
		couple.Marry();
	}
}
  • CGLIB动态代理

        什么是CGLIB代理?

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

下面我们来写一个CGLIB动态代理代码看看

 1.环境准备,准备一些需要的Jar

        cglib-nodep-2.2.jar:使用nodep包不需要关联asm的jar包,jar包内部包含asm的类.

        cglib-2.2.jar:使用此jar包需要关联asm的jar包,否则运行时报错.

2.目标类Person.java

public class Person {
    public void eat() {
        System.out.println("干饭了。。。。");
    }
}

3.CGLIB代理类CglibProxy.java

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements  MethodInterceptor{
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }
    public Object getProxy() {
        //作为代理对象目标类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        //生成类
        return enhancer.create();
    }

    /**
     *
     * @param o 代理对象
     * @param method 代理对象方法
     * @param objects 代理对象参数
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("饭前洗手");
        Object resulttarget = method.invoke(target, objects);
        System.out.println("饭后洗手");
        return resulttarget;
    }
}

4.最后我们建立一个测试类TestCglibProxy.java

public class TestCglibProxy {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy(new Person());
        Person person = (Person) cglibProxy.getProxy();
        person.eat();
    }
}
  • SpringAOP

    1.AOP是什么?

首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。

  • 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
  • 所谓的周边功能,比如性能统计,日志,事务管理等等

周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面

在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP,底层是JDK代理加CGLIB代理

      2. AOP当中的概念:

  • 切入点(Pointcut)
    在哪些类,哪些方法上切入
  • 通知(Advice)
    在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能)
  • 切面(Aspect)
    切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
  • 织入(Weaving)
    把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)

一张图来理解AOP的切入思想

 最后我们用代码来演示

        1.环境准备,在Spring的配置文件中AOP和CONTEXT加入约束

<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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="top.yunhuisu"/>
    <--  代理开启!-->
    <aop:aspectj-autoproxy/>
</beans>

        2.建立一个切面类Aspect.java,最后一个注释了的是Around可以代替前面的全部

package top.yunhuisu.aspect;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@org.aspectj.lang.annotation.Aspect
/**
 * 1、execution(): 表达式主体。
 * 2、第一个*号:表示返回类型, *号表示所有的类型。
 * 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,top.yunhuisu.service.*包、子孙包下所有类的方法。
 * 4、第二个*号:表示类名,*号表示所有的类。
 * 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数
 */
public class Aspect {
    //切面点方法
    @Pointcut("execution( * top.yunhuisu.service.*.*(..))")
    public void Cut() {
    }

    @Before(value = "Cut()")
    public void before() {
        System.out.println("前置通知。。。");
    }

    @AfterReturning(value = "Cut()")
    public void afterReturning() {
        System.out.println("返回通知。。。");
    }

    @AfterThrowing(value = "Cut()", throwing = "e")
    public void afterThrowing(Exception e) {
        System.out.println(e.getMessage());
    }

    @After(value = "Cut()")
    public void after() {
        System.out.println("最后通知。。。");
    }
/*
    @Around(value = "Cut()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) {
       try {
           System.out.println("前置通知。。。");
          proceedingJoinPoint.proceed();
        System.out.println("返回通知。。。");
        }catch (Throwable throwable) {
            throwable.printStackTrace();
         System.out.println("异常通知"+throwable.getMessage());
        }finally {
            System.out.println("最后通知。。。");
       }
   }
*/
}

        3.最后建立一个测试类testSpringaop.java

public class testSpringaop {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("Application.xml");
        UserService userService = app.getBean("userService",UserService.class);
        userService.Advice();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值