Spring的AOP详解

作为一个稀有的Java妹子,所写的所有博客都只是当作自己的笔记,留下证据自己之前是有用心学习的~哈哈哈哈(如果有不对的地方,也请大家指出,不要悄悄咪咪的不告诉我)

一、AOP

1.什么是AOP

1.AOP是面向切面编程,与OOP的纵向继承特点相比,AOP关注的是横向功能的扩展,OOP的最小单位是类,AOP的最小单位是切面。
2.AOP是为了提取出重复的代码,减少代码的冗余,切面就是这些重复代码提取后存放的位置。一般是解决系统级别的问题,如事务、日志监控、身份鉴别等,使得业务代码与这些系统级别的代码区分开。
3.所以AOP其实就是为了简化代码,是程序员更加的轻松,专注业务代码的逻辑。

2.AOP的实现

AOP的底层就是代理模式,代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

1.静态代理和动态代理

代理分为两种,它们都有增强方法的作用,但是静态代理是在编译期就为目标类添加了相应的功能,而动态代理是在运行期在内存里生成代理对象,不会改变目标类的字节码。

静态代理

需要手动的再写一个类去实现目标接口,然后对目标方法进行增强。

//目标接口
public interface MovieService {
	void paly();
}

//实现类
public class MovieServiceImpl implements MovieService {
	@Override
	public void paly() {
		System.out.println("电影开始拉");
	}
}

以上是原始的业务代码,比如这时候新的需求是在电影放映前插播一些广告,那么在不修改原来的paly方法的前提下,就采用静态代理的方式,创建另外一个类去实现接口。

public class MovieServiceProxy implements MovieService {

	private MovieServiceImpl movieService;
	public MovieServiceProxy(MovieServiceImpl movieService){
		this.movieService = movieService;
	}
	@Override
	public void paly() {
		playAd();
		movieService.paly();
	}

	public void playAd(){
		System.out.println("广告开始。。");
	}
}

public class Test {
	public static void main(String[] args) {
		MovieService movieService = new MovieServiceProxy(new MovieServiceImpl());
		movieService.paly();
	}
}

结果:

广告开始。。
电影开始拉

静态代理在不改变原有的方法前提下,需要新增一个类实现接口,然后在新的静态代理类中去实现方法的增强。

动态代理

动态代理的目的跟静态代理是一样的,就是想在不修改原有实现类的基础上增强方法,与静态代理的区别就是动态代理不需要手动的创建一个类,而是在程序运行时自动在内存中创建目标接口的代理类。

Spring AOP的动态代理有两种,JDK动态代理和CGLIB动态代理,前者是基于接口的代理,后者是基于类的代理。

1.jdk动态代理

主要是通过反射机制,为目标类生成代理类,核心类是:
·InvocationHandler 接口
·Proxy.newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)

1、 loader:类加载器
2、interfaces:被代理的接口
3、InvocationHandler:InvocationHandler对象

代理类实现了目标接口,调用InvocationHandler执行任务。
还是以刚才的Movie接口举例

//接口
public interface MovieService {
	void paly();
}

//实现类
public class MovieServiceImpl implements MovieService {
	@Override
	public void paly() {
		System.out.println("电影开始拉");
	}
}
public class DynamicService implements InvocationHandler {

	private Object object;

	public DynamicService(Object o){
		this.object = o;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("动态代理拉");
		method.invoke(object,args);
		return null;
	}
}

public class Test {
	public static void main(String[] args) {
		InvocationHandler invocationHandler1 = new DynamicService(new MovieServiceImpl());
		MovieService movieService1 = (MovieService)Proxy.newProxyInstance(MovieServiceImpl.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(), invocationHandler1);
		movieService1.paly();
	}
}

结果:

动态代理拉
电影开始拉

再定义一个接口

public interface TVService {
	void paly();
}

public class TVServiceImpl implements TVService {
	@Override
	public void paly() {
		System.out.println("电视剧开始拉");
	}
}

public class Test {
	public static void main(String[] args) {
		InvocationHandler invocationHandler1 = new DynamicService(new MovieServiceImpl());
		MovieService movieService1 = (MovieService)Proxy.newProxyInstance(MovieServiceImpl.class.getClassLoader(), MovieServiceImpl.class.getInterfaces(), invocationHandler1);
		movieService1.paly();
		//定义新的InvocationHandler
		InvocationHandler invocationHandler2 = new DynamicService(new TVServiceImpl());
		TVService tVService = (MovieService)Proxy.newProxyInstance(TVServiceImpl.class.getClassLoader(), TVServiceImpl.class.getInterfaces(), invocationHandler2);
		tVService.paly();
	}
}

结果:

动态代理拉
电影开始拉
动态代理拉
电视剧开始拉

那么这里并没有手动的创建MovieService和TVService的静态代理类,而是通过动态代理获取对应的代理类,并且jdk动态代理,代理类和目标类都实现同一个接口,方法名跟目标类是一样的,只是方法做了增强。

2.CGLIB动态代理

当目标类没有实现任何接口的时候,Spring AOP会选择使用 CGLIB 来动态代理目标类,主要就是通过代理类继承目标类,重写目标类的方法。
核心类是:
·MethodInterceptor 接口
·Enhancer 类

MethodInterceptor这个接口是一个拦截器,每个cglib的代理类都会有一个拦截器,当调用目标类的时候,就会被拦截器拦截,执行代理类的方法。

3.AOP的相关术语

1.通知(Advice)

就是公用的功能

2.连接点(JoinPoint)

允许通知的地方

3.切入点(Pointcut)

具体的某个方法

4.切面(Aspect)

通知和切入点的结合

5.目标(target)

目标类,就是被代理的类,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。

6.代理(Proxy)

aop的实现是依靠代理机制

4.实际的例子

在开发中也遇到过很多aop的例子,其实只要理解了aop是为了做什么的,就能发现代码里很多地方都使用了aop,比如Spring的事务,只要在类或者某个方法上加上@Transactional注解,就会开启事务,其实这就是aop为没一个使用该注解的类生成了代理类,代理类的每个方法在执行前会开启事务,执行完会提交事务。
接下来举一个我在实际开发中用到的一个很简单aop例子,就是为某些方法打印入参。

//这是切面
@Component
@Aspect
@Slf4j
public class MethodLogAspect {

	//定义切点,我自定义了一个注解,凡是使用了该注解的方法都会被当作切点
    @Pointcut("@annotation(com.jiebai.qqsk.member.aspect.MethodLog)")
    public void poinCut(){
    }
	//定义了前置通知和后置通知
    @Before("poinCut()")
    public void Before(JoinPoint jp){
        String methodName = jp.getSignature().getName();
        Map<String,String> map = new HashMap<>();
        String[] parameterNames = ((MethodSignature) jp.getSignature()).getParameterNames();
        Object[] args = jp.getArgs();
        if(parameterNames!=null && parameterNames.length>0){
            for(int i=0;i<parameterNames.length;i++){
                map.put(parameterNames[i],args[i].toString());
            }

        }
        log.info("进入方法"+methodName+",参数:"+ JSONObject.toJSONString(map));
    }

    @After("poinCut()")
    public void after(JoinPoint jp){
        String methodName = jp.getSignature().getName();
        log.info("退出方法"+methodName);
    }
}

在使用的时候只需要在方法上加上自定义注解即可

	@Override
    @MethodLog
    public Map<String, Object> userWithdrawGTC(BigDecimal amount, String type, Integer userId) throws Exception {


.....省略业务代码
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值