目录
AOP的作用:面向切面编程,可以不通过修改源代码的方式,在主干功能里面添加新的功能
1.AOP底层使用动态代理的两种情况
- 有接口情况,使用JDK动态代理
- 没有接口情况,使用CGLIB动态代理
2.JDK动态代理
- 创建接口和实现类实现方法
public interface UserDao { public int add(int a,int b); public String update(String id); }
public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
- 使用Proxy类创建接口代理对象
- 使用匿名内部类方式
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
// Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,
new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// return null;
// }
// });
- 外部类方式实现
public class JDKProxy { public static void main(String[] args) { //创建接口实现类 Class[] interfaces={ UserDao.class}; UserDaoImpl userDao=new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDapProxy(userDao)); System.out.println("result:"+dao.add(3, 5)); } } //创建代理对象,实现InvocationHandler接口 class UserDapProxy implements InvocationHandler{ //把要创建代理对象的类传递过来 //有参构造传递 private Object obj; public UserDapProxy(Object obj){ this.obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法调用之前添加功能 System.out.println("方法之前执行---"+method.getName()+" 传递进来的参数为:"+ Arrays.toString(args)); //被增强的方法执行 Object res= method.invoke(obj, args); //方法调用之后执行功能 System.out.println("增强方法之后。。。"+obj); return res; } }
3.AOP的操作术语
3.1连接点
类里面可以被增强的方法,称为连接点
3.2切入点
实际上被增强的方法,称为切入点
3.3通知(增强)
实际被增强的逻辑部分称为通知
通知的分类
1、前置通知
2、后置通知
3、环绕通知
4、异常通知
5、最终通知
3.4切面
把增强应用到切入点的过程
4.AOP操作
4.1引入相关的AOP依赖
4.2切入点表达式
(1)作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强 execution(* com.atguigu.dao.BookDao.add(..))
举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强 execution(* com.atguigu.dao.BookDao.* (..))
举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强 execution(* com.atguigu.dao.*.* (..))
4.3使用AspectJ注解进行方法增强
(1)创建类,定义方法
//被增强的类
@Component
public class User {}
(2)创建增强类
//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy {}
(3)配置xml文件
- 引入aop和context的名称空间
- 开启注解扫描
- 开启Aspect代理对象
(4)配置通知类型(通过注解配置)<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 开启注解扫描 --> <context:component-scan basepackage="com.atguigu.spring5.aopanno"></context:component-scan> <!--开启Aspect代理对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
//增强的类 @Component @Aspect//生成代理对象 public class UserProxy { //@Before注解表示作为前置通知 @Before(value = "execution(* com.hzj.aopAnno.User.add(..))") public void before(){ System.out.println("before....."); } //后置通知 @AfterReturning(value = "execution(* com.hzj.aopAnno.User.add(..))") public void AfterReturning(){ System.out.println("AfterReturning..."); } //最终通知 @After(value = "execution(* com.hzj.aopAnno.User.add(..))") public void after(){ System.out.println("after..."); } //异常通知 @AfterThrowing(value = "execution(* com.hzj.aopAnno.User.add(..))") public void AfterThrowing(){ System.out.println("AfterThrowing..."); } //环绕通知 @Around(value = "execution(* com.hzj.aopAnno.User.add(..))") public void Around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ System.out.println("环绕之前..."); proceedingJoinPoint.proceed(); System.out.println("环绕之后。。。"); } }
(5)抽取相同的切入点表达式
//抽取相同的切入点;要调用时直接写方法名就好 @Pointcut(value = "execution(* com.hzj.aopAnno.User.add(..))") public void pointdemo(){ } //@Before注解表示作为前置通知 @Before(value = "pointdemo()") public void before(){ System.out.println("before....."); }
*: 有多个类对同一个方法进行增强时,ky在增强类上使用@Order(数字)设置优先级,数字越小优先级越高
@Component
@Aspect
@Order(1)//当有多个类对同一个方法进行增强时,使用@Order设置优先级,数字越小优先级越高
public class PersonProxy {
5.使用xml配置文件进行增强(非注解)
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="book" class="com.hzj.aopxml.Book"></bean>
<bean id="bookProxy" class="com.hzj.aopxml.BookProxy"></bean>
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pct" expression="execution(* com.hzj.aopxml.Book.buy(..))"/>
<!--配置切面-->
<aop:aspect ref="bookProxy" >
<!--具体的增强方法-->
<aop:before method="before" pointcut-ref="pct"></aop:before>
</aop:aspect>
</aop:config>
</beans>