概念:
- AOP指的是面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。通俗点描述的话,就是:在不通过修改源代码的情况下,在主干功能里面添加新功能。
方式一:注解形式实现
一.新建maven项目,导入核心依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>demo</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-aop1</artifactId>
<dependencies>
<!--讲aop,导这个包-->
<!--Spring的AOP jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.19</version>
</dependency>
<!--如果需要使用@Aspect,导这个包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.19</version>
</dependency>
</dependencies>
</project>
二.新建UserDao和UserService的接口和实现类
package com.pro.dao;
public class UserDaoImpl implements UserDao {
public void insert(String name) {
System.out.println("-----"+name+",DaoImpl-------");
}
}
package com.pro.service;
import com.pro.dao.UserDao;
import com.pro.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
public void save(String name) {
userDao.insert(name);
System.out.println("-----"+name+",ServiceImpl-------");
}
}
三.配置好applicationContext.xml文件
- 在XML引入AOP的约束,这个是实现aop必须要导入的约束,结合自己的xml文件,对比观察发现,每一个约束,无论是MVC的约束还是aop的,都是xmlns里面有一条链接xsi里面有成对的两条链接,所以要导入约束,注意是三条。
<?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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> </beans>
下面这个是自己写的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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/> <!--自动代理-->
<bean id="asp" class="com.pro.util.MyAspect"/>
<bean id="userDao" class="com.pro.dao.UserDaoImpl"/>
<bean id="userService" class="com.pro.service.UserServiceImpl">
<!-- 这里为什么要写property 为了在UserServiceImpl里面不用new UserDao-->
<property name = "userDao" ref = "userDao"/>
</bean>
<!-- <aop:aspectj-autoproxy/><!–自动代理–>
<bean id="asp" class="com.pro.util.MyAspect"/>
<bean id="userDao" class="com.pro.dao.UserDaoImpl"/>
<bean id="userService" class="com.pro.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>-->
</beans>
execution函数介绍
在通知中通过value属性定义切点,通过execution函数,可以定义切点的方法切入
1、切入点:实际增强的方法
2、常用的表达式
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(1)execution(* com.tulun.bean.Book.show(..)) 表类里面的某一个方法
(2)execution(* com.tulun.bean.Book.*(..)) 表类某个包里类所有方法
(3)execution(* *.*(..)) 表示所有例:
-匹配所有类public方法 execution(public *.*(..))
-匹配指定包下所有类方法 execution(* com.tulun.bean.*(..)) (不包含子包)
- execution(* com.tulun.bean..*(..)) (包含包、子包下所有类)
-匹配指定类所有方法 execution(* com.tulun.bean.Book.*(..))
-匹配实现特定接口所有类方法 execution(* com.tulun.bean.Book+.*(..))
-匹配所有com开头的方法 execution(* com*(..))
四.写一个MyAspect工具类,用来模拟新添加的功能
package com.pro.util;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
//第一个*号后面要有一个空格
@Pointcut("execution(* com.pro.service..*.*(..))")//execution(* com.pro.service..*.*(..))实际上是一个方法
public void all(){
}
@Before("all()")//表示在pointCut这个切面下的方法执行前,都会先执行这个say方法
public void say(){
System.out.println("林强 ,你好!");
}
}
五.新建一个UserTest测试类
package com.pro.test;
import com.pro.service.UserService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
public static void main(String[] args) {
BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) beanFactory.getBean("userService");
userService.save("小星星");
}
}
六.执行效果:
。
方式二:xml文件里面配置来实现
- 区别就在于applicationContext.xml里面不一样自动代理不写,原本注解的方式改用配置xml文件,还有在添加的时候方法不要写注解,
<!-- aop:aspect标签 配置切面 把增强应用到切入点的过程 ref属性:指定增强 id属性:取名称 order属性:给多个增强排序 --> <!-- aop:pointcut标签 配置切入点 对于要进行增强的连接点称之为切入点 id属性:取名称 expression:切入点表达式 execution表达式 -->
<!-- <aop:aspectj-autoproxy/> <!–自动代理–>--> <aop:config> <aop:pointcut id="all" expression="execution(* com.pro.service..*.*(..))"/> <aop:aspect ref="asp"> <aop:after method="say" pointcut-ref="all"/> <aop:before method="say" pointcut-ref="all"/> </aop:aspect> </aop:config> <bean id="asp" class="com.pro.util.MyAspect"/> <bean id="userDao" class="com.pro.dao.UserDaoImpl"/> <bean id="userService" class="com.pro.service.UserServiceImpl"> <!-- 这里为什么要写property 为了在UserServiceImpl里面不用new UserDao--> <property name = "userDao" ref = "userDao"/> </bean> <!-- <aop:aspectj-autoproxy/><!–自动代理–> <bean id="asp" class="com.pro.util.MyAspect"/> <bean id="userDao" class="com.pro.dao.UserDaoImpl"/> <bean id="userService" class="com.pro.service.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean>--> </beans>
七.总结:
通过这两种种方式实现面向切面编程,就可以将模拟的MyAspect里面的新功能say方法,在不修改源代码的前提下,调用某个类(service)里面的方法时,在这个方法执行前或执行后增加进来。