Spring (AOP、静态代理、动态代理)

1. AOP

 

1.1 AOP简介

 

  1. AOP Aspect Oriented Programing 面向切面编程

  2. AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

  3. Spring中的Aop是纯Java来实现的,使用动态代理的方式增强代码

  4. Spring使用动态代理的机制是判断委托类是否实现了接口,如果实现了接口则使用jdk的动态代理,如果没有实现接口则使用cglib的动态代理

  5. AOP不是由Spring提出来的,是由AOP联盟定义的

 

1.2 AOP的专业术语

 

Joinpoint(连接点) :委托类中可以被增强的方法

Pointcut(切入点) :切点 ,要被增强的方法

Advice(通知/增强) :增强的代码

Target(目标对象) :委托对象

Weaving(织入) :增强应用切点的过程

Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面): 切点通知的结合

 

1.3 Spring中的AOP实现

1.3.1 传统的Spring的AOP

一个切点和一个通知的组合

1.3.2 基于Aspectj的AOP

  1. AspectJ是一个基于Java语言的面向切面的AOP框架

  2. Spring2.0以后新增了对AspectJ切点表达式支持

  3. @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面

  4. 新版本Spring框架,建议使用AspectJ方式来开发AOP

1.3.3 Aspectj的切点表达式

  • 语法:execution(表达式)

  • execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

  • public * *(..) ---检索所有的public方法

  • execution(“* cn.uplooking.spring4.demo1.dao.*(..)”) ---只检索当前包

  • execution(“* cn.uplooking.spring4.demo1.dao..*(..)”) ---检索包及当前包的子包.

 

1.3.4 Aspect的增强类型

  • @Before 前置通知,相当于BeforeAdvice

@Before("execution(* com.uplooking.aop.UserDao.add*(..))")

public void beforeAdvice() {

System.out.println("前置通知....");

}
  • @AfterReturning 后置通知,相当于AfterReturningAdvice

@AfterReturning(value = "execution(* com.uplooking.aop.UserDao.add*(..))", returning = "ret")

public void afterReturningAdvice(String ret) {

System.out.println("后置通知.." + ret);

}
  • @Around 环绕通知,相当于MethodInterceptor

@Around("execution(* com.uplooking.aop.UserDao.add*(..))")

public void arounrAdvice(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("环绕通知前..");

pjp.proceed();

System.out.println("环绕通知后..");

}
  • @AfterThrowing抛出通知,相当于ThrowAdvice

@AfterThrowing("execution(* com.uplooking.aop.UserDao.add*(..))")

public void throwAdvice() {

System.out.println("异常通知....");

}
  • @After 最终final通知,不管是否异常,该通知都会执行

@After(value = "execution(* com.uplooking.aop.UserDao.add*(..))")

public void afterAdvice() {

System.out.println("最终通知....");

}

 

1.4 AOP的编程(AspectJ)

 

1.4.1 导入pom依赖

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>4.3.12.RELEASE</version>

</dependency>



<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aspects</artifactId>

<version>4.3.12.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>4.3.12.RELEASE</version>

</dependency>

<dependency>



<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.12</version>

</dependency>



</dependencies>

 

引入约束

<?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: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.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="com.ma.aop"/>



<!--aop自动创建代理-->

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>



1.4.2(前置通知)

1.4.2.1 要被增强的类

package com.ma.aop;



import org.springframework.stereotype.Repository;



@Repository

public class UserDao {

public void addUser(){

System.out.println("添加用户...");

}

public void deleteUser(){

System.out.println("删除用户...");

}

public void updateUser(){

System.out.println("修改用户...");

}

public void selectUser(){

System.out.println("查找用户...");

}

}

1.4.2.2 定义切面

package com.ma.aop;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;

/**

* 切面 = 切点(切点表达式)+ 通知 (方法)

*/

@Aspect

@Component

public class MyAspect {



@Before("execution(* com.ma.aop.UserDao.addUser())")

public void beforeAdvice(){

System.out.println("前置通知...");

}



}

1.4.2.3测试

import com.ma.aop.UserDao;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringRunner;



@RunWith(SpringRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class TestUserDao {

@Autowired

private UserDao userDao;



@Test

public void testAdd(){

userDao.addUser();

}

}

 

1.4.2.5结果

 

1.4.3(后置通知)

 

1.4.3.1 要被增强的方法

package com.ma.aop;

import org.springframework.stereotype.Repository;

@Repository

public class UserDao {

public void addUser(){

System.out.println("添加用户...");

}

public String deleteUser(){

System.out.println("删除用户...");

return "已删除!";

}

public void updateUser(){

System.out.println("修改用户...");

}

public void selectUser(){

System.out.println("查找用户...");

}

}

1.4.3.2 定义切面

@AfterReturning(value = "execution(* com.ma.aop.UserDao.delete*())",returning = "ret")

public void afterReturningAdvice(String ret){

System.out.println("后置通知..."+"ret");

}

注意:可以得到返回值。

 

1.4.3.3 测试

@Test

public void testDelete(){

userDao.deleteUser();

}

 

1.4.3.4 结果

 

1.4.4(环绕通知)

 

1.4.4.1 要被增强的方法

package com.ma.aop;

import org.springframework.stereotype.Repository;

@Repository

public class UserDao {

public void addUser(){

System.out.println("添加用户...");

}

public String deleteUser(){

System.out.println("删除用户...");

return "已删除!";

}

public void updateUser(){

System.out.println("修改用户...");

}

public void selectUser(){

System.out.println("查找用户...");

}

}

1.4.4.2 定义切面

@Around("execution(* com.ma.aop.UserDao.update*())")

public void afterReturningAdvice(){

System.out.println("环绕通知...");

}

注意:此时环绕通知可以阻止目标方法的执行,需要对目标方法进行放行。

@Around("execution(* com.ma.aop.UserDao.update*())")

public void afterReturningAdvice(ProceedingJoinPoint pjp) throws Throwable {

System.out.println("环绕通知前...");

pjp.proceed();

System.out.println("环绕通知后...");

}

 

 

1.4.4.3 测试

@Test

public void testUpdate(){

userDao.updateUser();

}

 

1.4.4.4 效果

 

1.4.5(异常通知)

 

1.4.5.1 要被增强的方法

package com.ma.aop;

import org.springframework.stereotype.Repository;

@Repository

public class UserDao {

public void addUser(){

System.out.println("添加用户...");

}

public String deleteUser(){

System.out.println("删除用户...");

return "已删除!";

}

public void updateUser(){

System.out.println("修改用户...");

}

public void selectUser(){

int i = 10/0;

System.out.println("查找用户...");

}

}

1.4.5.2 定义切面

@AfterThrowing("execution(* com.ma.aop.UserDao.selectUser())")

public void throwAdvice(){

System.out.println("异常通知...");

}

 

 

1.4.5.3 测试

@Test

public void testSelect(){

userDao.selectUser();

}

 

1.4.5.4 效果

 

2.代理模式

不使用对象的真实操作,使用我们自己创建的代理对象来操作

 

2.1 静态代理

委托类和代理类共同实现同一个接口,在代理类中有委托类的对象。

1、公共接口

package com.ma.aop.agent;



public interface WindWomen {

String say();

}

 

 

2、委托类

package com.ma.aop.agent;

/**

* 委托类

*/

public class Pan implements WindWomen {



public String say() {

return "晚上十点小河边见......";

}

}



3、代理类

package com.ma.aop.agent;



public class Wang implements WindWomen {

private WindWomen windWomen;//委托对象

public Wang(WindWomen windWomen){

/**

* 在代理的构造器中持有一个委托的对象

*/

this.windWomen = windWomen;

}



public String say() {

System.out.println("她找我让我给你带个话:");

System.out.println(windWomen.say());

System.out.println("记得啊!");

return null;

}

}

 


4、测试类

package com.ma.aop.agent;



public class AgentTest {

public static void main(String[] args) {

Pan pan = new Pan();

Wang wang = new Wang(pan);

wang.say();

}

}



5、效果

 

 

 

 

2.1动态代理

 

2.2.1 基于原生的JDK的动态代理

package com.ma.aop.agent;



import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;



public class AgentTest {

public static void main(String[] args) {

final Pan pan = new Pan();

WindWomen windWomen = (WindWomen) Proxy.newProxyInstance(AgentTest.class.getClassLoader(), Pan.class.getInterfaces(), new InvocationHandler() {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

System.out.println("她找我让我给你带个话:");

Object object = method.invoke(pan,args);

System.out.println("记得啊!");

return object;

}

});

windWomen.say();

}

}



实现

 

 

 

效果

2.2.2 基于CGLIB的动态代理

因为原生的jdk的动态代理存在缺陷,代理类和委托类必须实现同一个接口

所以有个开源的动态代理框架出现了(CGLIB)

CGLIB不要求委托类必须实现接口:因为CGLIB底层是基于继承实现的

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值