AOP
- 面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- 通俗描述:不通过修改源代码方式,在主干功能里面添加新功能
一些概念:
概念 | 描述 |
---|---|
连接点 | 类中需要增强的方法 |
切入点 | 实际被真正增强的方法 |
通知(增强) | 向切点动态添加代码 |
切面 | 切点+通知 |
AOP 实现
AOP 底层使用动态代理:
- JDK 动态代理(有接口时使用)
- CGLIB 动态代理(无接口使用)
JDK 动态代理
创建接口实现类代理对象,增强类的方法
1、定义一个接口
public interface HelloWorld {
public void sayHelloWorld();
}
2、实现接口
public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHelloWorld() {
System.out.println("Hello World");
}
}
3、动态代理绑定和代理逻辑的实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample implements InvocationHandler {
//真实对象
private Object target = null;
/**
* 建立代理对象和真实对象的代理关系,并返回代理对象
* @param target 真实对象
* @return 代理对象
*/
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 代理方法逻辑
* @param proxy 代理对象
* @param method 当前调度方法
* @param args 当前方法参数
* @return 代理返回结果
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理逻辑方法");
System.out.println("在调度真是对象之前的服务");
//相当于sayHelloWorld()
Object obj = method.invoke(target, args);
System.out.println("在调度真是对象之后的服务");
return obj;
}
}
4、测试JDK动态代理
public class TestJdkProxy {
public static void main(String[] args) {
JdkProxyExample jdk = new JdkProxyExample();
HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
proxy.sayHelloWorld();
}
}
5、测试结果:
进入代理逻辑方法
在调度真是对象之前的服务
Hello World
在调度真是对象之后的服务
CGLIB 动态代理
创建子类的代理对象,增强类的方法
1、创建一个非抽象的、也没有实现接口的类
public class SayHelloImpl {
public void sayHello(String name) {
System.out.println("hello "+name);
}
}
2、CGLIB 动态代理
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyExample implements MethodInterceptor {
/**
* 生成 CGLIB 代理对象
* @param cls Class 类
* @return Class 类的 CGLIB 代理对象
*/
public Object getProxy(Class cls) {
//CGLIB enhancer 增强类对象
Enhancer enhancer = new Enhancer();
//设置超类地的类型
enhancer.setSuperclass(cls);
//定义代理逻辑对象为当前对象,要求当前对象实现 MethodInterceptor 方法
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
/**
* 代理逻辑方法
* @param proxy 代理对象
* @param method 方法
* @param args 方法参数
* @param methodProxy 方法代理
* @return 代理逻辑返回
* @throws Throwable 异常
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.err.println("调用真实对象前....");
//CGLIB 反射调用真实对象方法
Object result = methodProxy.invokeSuper(proxy, args);
System.err.println("调用真实对象后....");
return result;
}
}
3、测试 CGLIB 动态代理
public class TestCglibProxy {
public static void main(String[] args) {
CglibProxyExample cglib = new CglibProxyExample();
SayHelloImpl proxyObj = (SayHelloImpl) cglib.getProxy(SayHelloImpl.class);
proxyObj.sayHello("小明");
}
}
4、测试结果:
调用真实对象前....
hello 小明
调用真实对象后....
开发 Spring AOP
新建一个maven工程,并引入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
下面我们分别用xml和注解的方式来演示下aop的使用。
使用@AspectJ注解开发 Spring AOP
后面代码中用到的注解:
注解 | 说明 |
---|---|
@Before | 在被代理对象的方法之前调用,前置通知 |
@Around | 将被代理对象的方法封装起来,用环绕的方式取代它,可通过反射调用原有方法 |
@After | 在被代理对象的方法之后调用,后置通知 |
@AfterReturning | 在被代理对象的方法正常返回后调用,返回通知 |
@AfterThrowing | 在被代理对象的方法抛出异常后调用,异常通知 |
简单说下切点表达式:
比如:execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..))
- execution:表示执行方法时会触发
*
:代表任意返回类型的方法- top.wushanghui.aop.annotation.service.impl.RoleServiceImppl:代表类的全类名
- printRole:被拦截的方法名
(..)
:表示任意参数
Role
public class Role {
private Long id;
private String roleName;
private String note;
public Role(Long id, String roleName, String note) {
this.id = id;
this.roleName = roleName;
this.note = note;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", note='" + note + '\'' +
'}';
}
}
RoleService 接口
package top.wushanghui.aop.annotation.service;
import top.wushanghui.aop.annotation.pojo.Role;
public interface RoleService {
public void printRole(Role role, int sort);
}
RoleServiceImppl 实现类
package top.wushanghui.aop.annotation.service.impl;
import org.springframework.stereotype.Component;
import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.service.RoleService;
@Component
public class RoleServiceImppl implements RoleService {
@Override
public void printRole(Role role, int sort) {
System.out.println("{id = " + role.getId() + ", roleName = " + role.getRoleName() + ", note = " + role.getNote() + "}");
System.out.println("sort" + sort);
}
}
RoleVerifier 接口
package top.wushanghui.aop.annotation.verifier;
import top.wushanghui.aop.annotation.pojo.Role;
public interface RoleVerifier {
public boolean verify(Role role);
}
RoleVerifierImpl 实现类
package top.wushanghui.aop.annotation.verifier.impl;
import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.verifier.RoleVerifier;
public class RoleVerifierImpl implements RoleVerifier {
@Override
public boolean verify(Role role) {
return role != null;
}
}
RoleAspect 切面类
package top.wushanghui.aop.annotation.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import top.wushanghui.aop.annotation.pojo.Role;
import top.wushanghui.aop.annotation.service.impl.RoleServiceImppl;
import top.wushanghui.aop.annotation.verifier.RoleVerifier;
import top.wushanghui.aop.annotation.verifier.impl.RoleVerifierImpl;
@Aspect
public class RoleAspect {
@DeclareParents(value = "top.wushanghui.aop.annotation.service.impl.RoleServiceImppl+", defaultImpl = RoleVerifierImpl.class)
private RoleVerifier roleVerifier;
@Pointcut("execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..))")
public void print() {
}
@Before("execution(* top.wushanghui.aop.annotation.service.impl.RoleServiceImppl.printRole(..)) && args(role, sort)")
public void before(Role role, int sort) {
System.out.println("before ... role: " + role + ", sort: " + sort);
}
@After("print()")
public void after() {
System.out.println("after ... ");
}
@AfterReturning("print())")
public void afterReturning() {
System.out.println("afterReturning ... ");
}
@AfterThrowing("print()")
public void afterThrowing() {
System.out.println("afterThrowing ... ");
}
@Around("print()")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("around before ... ");
try {
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around after ... ");
}
}
AopConfig 配置类
package top.wushanghui.aop.annotation.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import top.wushanghui.aop.annotation.aspect.RoleAspect;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("top.wushanghui.aop.annotation")
public class AopConfig {
@Bean
public RoleAspect getRoleAspect() {
return new RoleAspect();
}
}
测试:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
RoleService roleService = ctx.getBean(RoleService.class);
Role role = new Role(1L, "admin", "note1");
RoleVerifier roleVerifier = (RoleVerifier) roleService;
if (roleVerifier.verify(role)) {
roleService.printRole(role, 2);
}
System.out.println("============================");
// 测试异常通知
role = null;
if (roleVerifier.verify(role)) {
roleService.printRole(role, 2);
}
System.out.println("============================");
}
}
结果:
around before ...
before ... role: Role{id=1, roleName='admin', note='note1'}, sort: 2
{id = 1, roleName = admin, note = note1}
sort2
afterReturning ...
after ...
around after ...
============================
============================
多个切面
MultiBean 接口
package top.wushanghui.multi.bean;
public interface MultiBean {
public void testMulti();
}
MultiBeanImpl 实现类
package top.wushanghui.multi.bean.impl;
import org.springframework.stereotype.Component;
import top.wushanghui.multi.bean.MultiBean;
@Component
public class MultiBeanImpl implements MultiBean {
@Override
public void testMulti() {
System.out.println("测试多个切面!");
}
}
三个切面
package top.wushanghui.multi.aspect;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
@Aspect
@Order(2)
public class Aspect1 {
@Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
public void print() {
}
@Before("print()")
public void before() {
System.out.println("before 1 ... ");
}
@After("print()")
public void after() {
System.out.println("after 1 ... ");
}
@AfterReturning("print())")
public void afterReturning() {
System.out.println("afterReturning 1 ... ");
}
@AfterThrowing("print()")
public void afterThrowing() {
System.out.println("afterThrowing 1 ... ");
}
}
package top.wushanghui.multi.aspect;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
@Aspect
@Order(1)
public class Aspect2 {
@Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
public void print() {
}
@Before("print()")
public void before() {
System.out.println("before 2 ... ");
}
@After("print()")
public void after() {
System.out.println("after 2 ... ");
}
@AfterReturning("print())")
public void afterReturning() {
System.out.println("afterReturning 2 ... ");
}
@AfterThrowing("print()")
public void afterThrowing() {
System.out.println("afterThrowing 2 ... ");
}
}
package top.wushanghui.multi.aspect;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
@Aspect
@Order(3)
public class Aspect3 {
@Pointcut("execution(* top.wushanghui.multi.bean.impl.MultiBeanImpl.testMulti(..))")
public void print() {
}
@Before("print()")
public void before() {
System.out.println("before 3 ... ");
}
@After("print()")
public void after() {
System.out.println("after 3 ... ");
}
@AfterReturning("print())")
public void afterReturning() {
System.out.println("afterReturning 3 ... ");
}
@AfterThrowing("print()")
public void afterThrowing() {
System.out.println("afterThrowing 3 ... ");
}
}
MultiConfig 配置类
package top.wushanghui.multi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import top.wushanghui.multi.aspect.Aspect1;
import top.wushanghui.multi.aspect.Aspect2;
import top.wushanghui.multi.aspect.Aspect3;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("top.wushanghui.multi")
public class MultiConfig {
@Bean
public Aspect1 getAspect1() {
return new Aspect1();
}
@Bean
public Aspect2 getAspect2() {
return new Aspect2();
}
@Bean
public Aspect3 getAspect3() {
return new Aspect3();
}
}
测试:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MultiConfig.class);
MultiBean multiBean = ctx.getBean(MultiBean.class);
multiBean.testMulti();
}
}
结果:
before 2 ...
before 1 ...
before 3 ...
测试多个切面!
afterReturning 3 ...
after 3 ...
afterReturning 1 ...
after 1 ...
afterReturning 2 ...
after 2 ...
使用 XML 配置开发Spring AOP
xml 配置AOP元素
AOP配置元素 | 说明 |
---|---|
aop:config | 顶层的AOP配置元素,它是aop配置的开始 |
aop:aspect | 定义一个切面 |
aop:pointcut | 定义切点 |
aop:before | 定义前置通知 |
aop:after | 定义后置通知 |
aop:after-returning | 定义返回通知 |
aop:after-throwing | 定义异常通知 |
aop:around | 定义环绕方式 |
aop:declare-parents | 给通知引入新的额外接口,增强功能 |
实体类 Role
package top.wushanghui.aop.xml.pojo;
public class Role {
private Long id;
private String roleName;
private String note;
public Role(Long id, String roleName, String note) {
this.id = id;
this.roleName = roleName;
this.note = note;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
", note='" + note + '\'' +
'}';
}
}
RoleService 接口
package top.wushanghui.aop.xml.service;
import top.wushanghui.aop.xml.pojo.Role;
public interface RoleService {
public void printRole(Role role, int sort);
}
RoleServiceImppl 实现类
package top.wushanghui.aop.xml.service.impl;
import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.service.RoleService;
public class RoleServiceImppl implements RoleService {
@Override
public void printRole(Role role, int sort) {
System.out.println("{id = " + role.getId() + ", roleName = " + role.getRoleName() + ", note = " + role.getNote() + "}");
System.out.println("sort" + sort);
}
}
RoleVerifier 接口
用来检测角色是否为空,后面会有它的实现类
package top.wushanghui.aop.xml.verifier;
import top.wushanghui.aop.xml.pojo.Role;
public interface RoleVerifier {
public boolean verify(Role role);
}
RoleVerifierImpl 实现类
package top.wushanghui.aop.xml.verifier.impl;
import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.verifier.RoleVerifier;
public class RoleVerifierImpl implements RoleVerifier {
@Override
public boolean verify(Role role) {
return role != null;
}
}
XmlAspect 这时一个切面类
package top.wushanghui.aop.xml.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import top.wushanghui.aop.xml.pojo.Role;
import top.wushanghui.aop.xml.verifier.RoleVerifier;
public class XmlAspect {
private RoleVerifier roleVerifier;
public void before(Role role, int sort) {
System.out.println("before ... role: " + role + ", sort: " + sort);
}
public void after() {
System.out.println("after ... ");
}
public void afterReturning() {
System.out.println("afterReturning ... ");
}
public void afterThrowing() {
System.out.println("afterThrowing ... ");
}
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("around before ... ");
try {
joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("around after ... ");
}
}
spring-aop.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: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">
<bean id="xmlAspect" class="top.wushanghui.aop.xml.aspect.XmlAspect"/>
<bean id="roleService" class="top.wushanghui.aop.xml.service.impl.RoleServiceImppl"/>
<bean id="roleVerifier" class="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>
<aop:config>
<!--引用xmlAspect作为切面-->
<aop:aspect ref="xmlAspect">
<!--定义切点-->
<aop:pointcut id="print" expression="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..))"/>
<aop:before method="before" pointcut="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..)) and args(role, sort)"/>
<!--定义通知,引入切点-->
<aop:after method="after" pointcut-ref="print"/>
<aop:after-returning method="afterReturning" pointcut-ref="print"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="print"/>
<aop:around method="around" pointcut-ref="print"/>
<aop:declare-parents types-matching="top.wushanghui.aop.xml.service.impl.RoleServiceImppl+"
implement-interface="top.wushanghui.aop.xml.verifier.RoleVerifier"
default-impl="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>
</aop:aspect>
</aop:config>
</beans>
首先需要一些类注入到spring 容器中,
<bean id="xmlAspect" class="top.wushanghui.aop.xml.aspect.XmlAspect"/>
<bean id="roleService" class="top.wushanghui.aop.xml.service.impl.RoleServiceImppl"/>
<bean id="roleVerifier" class="top.wushanghui.aop.xml.verifier.impl.RoleVerifierImpl"/>
使用<aop:config>
配置aop,首先引用切面<aop:aspect ref="xmlAspect">
,大家可以看到我定义了一个公共的切点:
<aop:pointcut id="print" expression="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..))"/>
这样在五种通知中都可以引入,比如<aop:after method="after" pointcut-ref="print"/>
后置通知中pointcut-ref="print"
,当然你也可以想before 前置通知中,自己定义切点,<aop:before method="before" pointcut="execution(* top.wushanghui.aop.xml.service.impl.RoleServiceImppl.printRole(..)) and args(role, sort)"/>
需要注意的是and args(role, sort)"
我们使用and args来获取参数。
测试:
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-aop.xml");
RoleService roleService = ctx.getBean(RoleService.class);
Role role = new Role(2L, "admin", "note1");
RoleVerifier roleVerifier = (RoleVerifier) roleService;
if (roleVerifier.verify(role)) {
roleService.printRole(role, 2);
}
System.out.println("============================");
// 测试异常通知
role = null;
if (roleVerifier.verify(role)) {
roleService.printRole(role, 2);
}
System.out.println("============================");
}
}
结果:
before ... role: Role{id=2, roleName='admin', note='note1'}, sort: 2
around before ...
{id = 2, roleName = admin, note = note1}
sort2
around after ...
afterReturning ...
after ...
============================
============================
参考:<<Java EE互联网轻量级框架整合开发>>