springAOP的实现方式
1.原生JDK实现
(1)定义1个切面类
package com.springAOP.aop01;
public class MyAspect {
public void before(){
System.out.println("this is before");
}
public void after(){
System.out.println("this is after");
}
}
(2)编写一个代理工厂UserServiceFactory
Proxy的静态方法newProxyInstance()方法,可以实现静态代理
package com.springAOP.aop01;
import com.springAOP.service.IUserService;
import com.springAOP.service.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class UserServiceFactory {
public static IUserService getUserService() {
IUserService service = new UserServiceImpl();
MyAspect myAspect = new MyAspect();
/**
* Proxy的静态方法newProxyInstance()方法,可以实现静态代理
* 含有三个参数
* 1. 类加载器, 当前类对象的getClassLoader()
* 2. 该对象的接口们
* 3. 调用处理类,回调接口
*/
IUserService userService = (IUserService)
//getClassLoader():取得该Class对象的类装载器
Proxy.newProxyInstance(UserServiceFactory.class.getClassLoader(), service.getClass().getInterfaces(), new InvocationHandler() {
/**
* 调用处理类,回调接口
* 该回调方法含有三个参数
* @param proxy 第一个是代理对象
* @param method 第二个是代理方法对象
* @param args 第三个是代理方法的参数列表
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在主任务前加上辅助功能
myAspect.before();
// 打印调用的方法名,和参数列表
System.out.println(method.getName() + "\t" + Arrays.toString(args) + "\t");
// 通过方法名和参数列表 调用 UserServiceImpl下匹配的方法
Object obj = method.invoke(service, args);
// 在主任务后加上辅助功能
myAspect.after();
return obj;
}
});
return userService;
}
}
(3)测试运行
public class TestAOP01 {
@Test
public void test1(){
IUserService ius = new UserServiceImpl();
ius.getAllUsers();
System.out.println("-----------------");
ius.getUserByUid(1);
System.out.println("-----------------");
ius.getUsersByPage(1, 3);
System.out.println("-----------------");
User u = new User();
ius.saveUser(u);
System.out.println("-----------------");
ius.updateUser(u);
System.out.println("-----------------");
ius.deleteUser(1);
System.out.println("-----------------");
}
@Test
public void testAOP01(){
IUserService ius = UserServiceFactory.getUserService();
ius.getAllUsers();
System.out.println("-----------------");
ius.getUserByUid(1);
System.out.println("-----------------");
ius.getUsersByPage(1, 3);
System.out.println("-----------------");
User u = new User();
ius.saveUser(u);
System.out.println("-----------------");
ius.updateUser(u);
System.out.println("-----------------");
ius.deleteUser(1);
System.out.println("-----------------");
}
}
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KIrSI63o-1665278170688)(springAOP.assets/image-20220920210316272.png)]
可以看出,通过反射来让静态工厂来代理来实现AOP的功能
2.使用Enhancer增强类来实现
// aop的第二种实现方式,使用Enhancer增强类
public class UserServiceFactory {
public static IUserService getUserService(){
// 总共分为四个步骤:
IUserService ius = new UserServiceImpl();
// 1. 创建Enhander增强类对象
Enhancer eh = new Enhancer();
// 2. 设置增强类对象的superClass,设置当前对象的父接口
eh.setSuperclass(IUserService.class);
// 3. 设置增强类对象的回调接口
// 回调接口包含一个回调方法intercept,
eh.setCallback(new MethodInterceptor() {
/**
* 回调方法,该方法含有四个参数:
* @param o 1. 代理对象
* @param method 2. 方法对象
* @param objects 3. 方法的参数列表
* @param methodProxy 4. 给每个方法设置了代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("this is before");
Object obj = method.invoke(ius, objects);
System.out.println("this is after");
return obj;
}
});
// 使用Enhance对象的create()方法创建我们需要的对象,
// 由于第二步设置了当前对象的superClass,
IUserService myIUS = (IUserService) eh.create();
return myIUS;
}
}
(2.)测试
public class TestAOP02 {
@Test
public void testAOP02(){
IUserService ius = UserServiceFactory.getUserService();
ius.getAllUsers();
System.out.println("=============");
ius.getUserByUid(9);
System.out.println("=============");
ius.getUsersByPage(3, 20);
System.out.println("=============");
User u = new User();
ius.saveUser(u);
System.out.println("=============");
ius.updateUser(u);
System.out.println("=============");
ius.deleteUser(1);
System.out.println("=============");
}
}
3.使用ProxyFactoryBean来实现代理
1.定义1个切面类
public class MyAspect implements MethodInterceptor {
public void before(){
System.out.println("this is before");
}
public void after(){
System.out.println("this is after");
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
// proceed()指的是要处理的业务方法,在之前和之后可以分别添加辅助功能代码
Object obj = invocation.proceed();
after();
return obj;
}
}
2.配置xml文件
cglib: code generation library:是一个强大的代码生产类库,效率更高
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="ius" class="com.springAOP.service.impl.UserServiceImpl" />
<bean id="ma" class="com.springAOP.aop03.MyAspect" />
<!--
使用ProxyFactoryBean来实现代理
设置了四个属性:
target:目标,在哪个对象之上实现代理
interfaces:接口们,如果接口有多个,可以按照集合方式注入
<list>
<value>com.springAOP.service.IUserService</value>
<value>com.springAOP.service.IUserService</value>
<value>com.springAOP.service.IUserService</value>
<value>com.springAOP.service.IUserService</value>
</list>
interceptorNames:拦截名称,该名称对应的类要实现一个接口MethodInterceptor,
实现该接口,必须实现该接口的抽象方法invoke();
optimize:是否强制使用cglib动态代理
cglib: code generation library:是一个强大的代码代码生产类库,效率更高
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="ius" />
<property name="interfaces" value="com.springAOP.service.IUserService" />
<property name="interceptorNames" value="ma" />
<property name="optimize" value="true" />
</bean>
</beans>
3.测试运行
public class TestAOP03 {
@Test
public void testAOP03(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop03.xml");
IUserService ius = ac.getBean("proxy", IUserService.class);
ius.getAllUsers();
System.out.println("================");
ius.getUserByUid(1);
System.out.println("================");
ius.getUsersByPage(1, 5);
System.out.println("================");
User u = new User();
System.out.println("================");
ius.saveUser(u);
System.out.println("================");
ius.updateUser(u);
System.out.println("================");
ius.deleteUser(1);
}
}
4.aop:config实现代理
1.切面类
public class MyAspect implements MethodInterceptor {
public void before(){
System.out.println("this is before");
}
public void after(){
System.out.println("this is after");
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
Object obj = invocation.proceed();
after();
return obj;
}
}
2.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="ius" class="com.springAOP.aop04.service.impl.UserServiceImpl" />
<bean id="ma" class="com.springAOP.aop04.service.MyAspect" />
<!--
aop:config实现代理,注意需要添加对象的ns和xsi
proxy-target-class="true":强制使用cgLib的动态代理
aop:pointcut: 定义一个切点类
expression指定了一种统配规则
* com.springAOP.aop04.service.*.*(..)
返回值 包.接口.方法名(参数列表)
expression="execution(boolean com.springAOP.aop04.service.*.*(..))"
expression="execution(boolean com.springAOP.aop04.service.*.*(..))"
expression="execution(java.util.List com.springAOP.aop04.service.*.*(..))“
expression="(execution(java.util.List com.springAOP.aop04.service.*.*(..)) or execution(boolean com.springAOP.aop04.service.*.*(..)))"
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="pt" expression="(execution(java.util.List com.springAOP.aop04.service.*.*(..)) or execution(boolean com.springAOP.aop04.service.*.*(..)))"/>
<aop:advisor advice-ref="ma" pointcut-ref="pt" />
</aop:config>
</beans>
@Test
public void testAOP04(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop04.xml");
IUserService ius = ac.getBean("ius", IUserService.class);
ius.getAllUsers();
System.out.println("================");
ius.getUserByUid(1);
System.out.println("================");
ius.getUsersByPage(1, 5);
System.out.println("================");
User u = new User();
System.out.println("================");
ius.saveUser(u);
System.out.println("================");
ius.updateUser(u);
System.out.println("================");
ius.deleteUser(1);
}
5.JoinPoint加入点
public class MyAspect {
/**
* JoinPoint加入点,可以动态获取每一个业务方法中的所有信息
* getArgs()方法可以获取业务方法的参数列表
* getTarget()方法可以获取被代理对象的信息
* toString()可以获取业务方法的具体信息
* @param jp
*/
public void before(JoinPoint jp){
System.out.println(Arrays.toString(jp.getArgs()) + " " + jp.getTarget() + " " + jp.toString());
System.out.println("this is before");
}
public void after(){
System.out.println("this is after");
}
public Object around(ProceedingJoinPoint pjp){
try {
System.out.println("this is around before");
Object obj = pjp.proceed();
System.out.println("this is around after");
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
public void myReturn(Object obj){
System.out.println("this is my return " + obj);
}
public void myThrow(Throwable e){
System.out.println("this is my throw " + e);
}
}
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="ius" class="com.springAOP.aop05.service.impl.UserServiceImpl" />
<bean id="ma" class="com.springAOP.aop05.service.MyAspect" />
<aop:config proxy-target-class="true">
<aop:aspect ref="ma">
<aop:pointcut id="mpt" expression="execution(* com.springAOP.aop05.service.*.*(..))"/>
<!--
五种通知方式实现AOP
前置通知,在业务方法之前执行辅助功能
后置通知,在业务方法之后执行辅助功能
环绕通知,分别在业务方法之前和之后执行辅助功能,所对应的业务方法需要一个ProceddingJoinPoint参数
带有返回值的通知,可以动态拿到不同业务方法的返回值,需要Object obj对象用来接收每个方法各自的返回值
带有异常抛出的通知,可以获取异常信息,需要定义Throwable对象来接收异常对象
-->
<aop:before method="before" pointcut-ref="mpt" />
<aop:after method="after" pointcut-ref="mpt" />
<aop:around method="around" pointcut-ref="mpt" />
<aop:after-returning method="myReturn" pointcut-ref="mpt" returning="obj" />
<aop:after-throwing method="myThrow" pointcut-ref="mpt" throwing="e" />
</aop:aspect>
</aop:config>
</beans>
测试
public class TestAOP05 {
@Test
public void testAOP05(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop05.xml");
IUserService ius = ac.getBean("ius", IUserService.class);
ius.getAllUsers();
System.out.println("================");
ius.getUserByUid(1);
System.out.println("================");
ius.getUsersByPage(1, 5);
System.out.println("================");
User u = new User();
System.out.println("================");
ius.saveUser(u);
System.out.println("================");
ius.updateUser(u);
System.out.println("================");
ius.deleteUser(1);
}
}
6.注解方式
@Component//声明这是一个组件
@Aspect//声明这是一个切面类
public class MyAspect {
@Pointcut(value = "execution(* com.springAOP.aop06.service.*.*(..))")
public void all(){}
/**
* JoinPoint加入点,可以动态获取每一个业务方法中的所有信息
* getArgs()方法可以获取业务方法的参数列表
* getTarget()方法可以获取被代理对象的信息
* toString()可以获取业务方法的具体信息
* @param jp
*/
@Before("all()")
public void before(JoinPoint jp){
System.out.println(Arrays.toString(jp.getArgs()) + " " + jp.getTarget() + " " + jp.toString());
System.out.println("this is before");
}
@After("all()")
public void after(){
System.out.println("this is after");
}
@Around("all()")
public Object around(ProceedingJoinPoint pjp){
try {
System.out.println("this is around before");
Object obj = pjp.proceed();
System.out.println("this is around after");
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
@AfterReturning(value = "all()", returning = "obj")
public void myReturn(Object obj){
System.out.println("this is my return " + obj);
}
@AfterThrowing(value = "all()", throwing = "e")
public void myThrow(Throwable e){
System.out.println("this is my throw " + e);
}
}
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">
<!--
context:component-scan: 上下文的组件扫描
base-package,指定哪个包下的所有组件都将被扫描到Spring容器中
想要被扫描到容器中,必须给类添加@Component注解
-->
<context:component-scan base-package="com.springAOP.aop06.service" />
<!--
aop:aspectj-autoproxy:切面的自动代理
-->
<aop:aspectj-autoproxy />
</beans>
测试
public class TestAOP06 {
@Test
public void testAOP06(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop06.xml");
IUserService ius = ac.getBean("us", IUserService.class);
ius.getAllUsers();
System.out.println("================");
ius.getUserByUid(1);
System.out.println("================");
ius.getUsersByPage(1, 5);
System.out.println("================");
User u = new User();
System.out.println("================");
ius.saveUser(u);
System.out.println("================");
ius.updateUser(u);
System.out.println("================");
ius.deleteUser(1);
}
}
7.实现BeanPostProcessor接口
1.切面类
public class MyAspect {
public void before(){
System.out.println("this is before");
}
public void after(){
System.out.println("this is after");
}
}
2.新增一个类MyBeanPostProcessor实现BeanPostProcessor接口
/**
* 新增一个类MyBeanPostProcessor实现BeanPostProcessor接口
* 需要重写两个方法postProcessAfterInitialization和postProcessBeforeInitialization
* 这两个方法中的参数bean对应的是spring容器中任何业务对象
*/
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("this is postProcessAfterInitialization");
MyAspect ma = new MyAspect();
return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ma.before();
Object obj = method.invoke(bean, args);
ma.after();
return obj;
}
});
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("this is postProcessBeforeInitialization");
return bean;
}
}
测试
public class TestAOP07 {
@Test
public void testAOP07(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop07.xml");
IUserService ius = ac.getBean("ius", IUserService.class);
ius.getAllUsers();
System.out.println("================");
ius.getUserByUid(1);
System.out.println("================");
ius.getUsersByPage(1, 5);
System.out.println("================");
User u = new User();
System.out.println("================");
ius.saveUser(u);
System.out.println("================");
ius.updateUser(u);
System.out.println("================");
ius.deleteUser(1);
}
}