AOP部分的知识相比IoC部分的要少很多,也很容易理解~
AOP基本概念
AOP,面向切面编程,AOP功能的通俗理解:不修改源代码但可以实现功能新增。
作用:降低耦合度。
AOP底层原理
技术:动态代理
实现:有接口的情况,通过JDK动态代理;没有接口,通过CGLIB动态代理
JDK动态代理

1.创建接口和接口对应的实现类
public interface UserDao {
public int add(int a, int b);
public String show(String str);
}
public class UserDaoImpl implements UserDao {
@Override
public int add(int a, int b) {
System.out.println("add方法执行...");
return a + b;
}
@Override
public String show(String str) {
System.out.println("show方法执行...");
return str;
}
}
2.通过实现InvocationHandler接口创建代理类
3.调用Proxy类的静态方法newProxyInstance生成代理对象
public class JDKProxy {
public static void main(String[] args) {
//创建接口实现类对象
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;
}
});*/
//实际业务中,调用代理对象的那个对象通常是通过前端等方式获取的
UserDao userDao = new UserDaoImpl();
//实现InvocationHandler接口,创建代理类方式
UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int add = userDaoProxy.add(6, 6);
System.out.println("ending...");
}
}
//创建代理对象
class UserDaoProxy implements InvocationHandler {
private Object obj;
//通过有参构造将调用代理的对象进行传参,获取对应的对象
public UserDaoProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("AOP切面实现方法增强:核心业务逻辑执行之前... ...");
System.out.println(method.getName() + "::" + Arrays.toString(args));
Object result = method.invoke(obj, args);
System.out.println("AOP切面实现方法增强:核心业务逻辑执行之后... ...");
return result;
}
}

AOP术语
1.连接点:可以被通知或增强的方法
2.切入点:实际被通知或增强的方法
3.通知(增强):通知或增强的方法,前置通知、后置通知、异常通知、环绕通知、最终通知...
4.切面:一个动作!把通知或增强切入到切入点的过程
AOP操作
实现:Spring框架中一般基于AspectJ框架实现,AspectJ是独立于Spring的框架。
两种实现方式
基于xml配置或注解方式(开发中实际使用的一般都是注解方式)
导入依赖:spring-aspects、aspectj相关

切入点表达式
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
权限修饰符通常是*,返回类型通常省略,方法名称可以写*,参数列表通常写..
eg.execution(* com.coffeeship.dao.UserDao.*(..))
表示对com.coffeeship.dao.UserDao类中的所有方法进行增强。
AspectJ注解方式实现
1.创建需要被增强的类,定义一个方法用作切入点
@Component
public class User {
public void add() {
System.out.println("add... ...");
}
}
2.创建增强类,类上添加注解@Aspect
3.定义增强方法,方法上添加注解@Before或@After等,并使用切入点表达式
@Component
@Aspect
public class UserProxy {
@Before("execution(* com.coffeeship.dao.User.add(..))")
public void before() {
System.out.println("before add ... ...");
}
}
4.配置文件中开启生成代理对象的功能
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" 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.coffeeship"/>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy/>
</beans>
测试以下
@Test
public void test01() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("aopconfig.xml");
User user = applicationContext.getBean("user", User.class);
user.add();
}

其他通知或增强执行顺序
@Component
@Aspect
public class UserProxy {
//方法执行之前执行
@Before("execution(* com.coffeeship.dao.User.add(..))")
public void before() {
System.out.println("before add ... ...");
}
//方法执行之后执行
@After("execution(* com.coffeeship.dao.User.add(..))")
public void after() {
System.out.println("after add ... ...");
}
//方法异常后执行
@AfterThrowing("execution(* com.coffeeship.dao.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing add ... ...");
}
//方法返回值之后执行
@AfterReturning("execution(* com.coffeeship.dao.User.add(..))")
public void afterReturning() {
System.out.println("afterReturning add ... ...");
}
//环绕通知
@Around("execution(* com.coffeeship.dao.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before add ... ...");
proceedingJoinPoint.proceed();
System.out.println("around after add ... ...");
}
}

注意@After和@AfterReturning的执行顺序和区别
异常发生时的执行顺序:有异常时,@AfterReturning就没执行了,但@After总会执行,@After是最终通知,可以理解成try-catch-finally中的finally。

公共切入点抽取,重用切入点
@Pointcut("execution(* com.coffeeship.dao.User.add(..))")
public void pointcut() {}
//方法执行之前执行
// @Before("execution(* com.coffeeship.dao.User.add(..))")
@Before("pointcut()")
public void before() {
System.out.println("before add ... ...");
}
设置增强类的优先级
@Order(优先级数),数越小,优先级越高
@Component
@Aspect
@Order(1)
public class AdminProxy {
@Pointcut("execution(* com.coffeeship.dao.User.add(..))")
public void pointcut() {}
//方法执行之前执行
// @Before("execution(* com.coffeeship.dao.User.add(..))")
@Before("pointcut()")
public void before() {
System.out.println("Admin before add ... ...");
}
}
完全注解开发
@ComponentScan(basePackages = {"com.coffeeship"}) 表明开启组件扫描
@EnableAspectJAutoProxy(proxyTargetClass = true) 表明开启AOP生成代理对象
@Configuration
@ComponentScan(basePackages = {"com.coffeeship"})
//@EnableAspectJAutoProxy 开启AOP生成代理对象,proxyTargetClass默认是true
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AOPConfig {
}
@Test
public void test02() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AOPConfig.class);
User user = applicationContext.getBean("user", User.class);
user.add();
}
AspectJ配置文件实现(了解即可)
1.创建增强类和被增强类,定义增强类的增强方法和被增强类的被增强方法
public class Book {
public void buy() {
System.out.println("buy books... ...");
}
}
public class BookProxy {
public void before() {
System.out.println("before buying ... ...");
}
}
2.XML文件配置bean和AOP增强
配置切入点 → 配置切面:增强类的bean和增强类型、切入点
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true" 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.coffeeship.dao.Book"/>
<bean id="bookProxy" class="com.coffeeship.aop.BookProxy"/>
<!--配置AOP增强-->
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.coffeeship.dao.Book.buy(..))"/>
<aop:aspect ref="bookProxy">
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>

2825

被折叠的 条评论
为什么被折叠?



