1、AOP(面向切面编程)
1.1、作用:
AOP 主要应用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用
1.2、特点:
-
降低模块与模块之间的耦合度,提高业务代码的聚合度(高内聚低耦合)
-
提高了代码的复用性
-
提高系统的扩展性(高版本兼容低版本)
-
可以在不影响原有的功能基础上添加新的功能
1.3、底层实现:
动态代理(JDK + CGLIB)
1.4、基本概念:
- Joinpoint(连接点):目标对象的所有方法
- Pointcut(切入点):与表达式匹配的方法
- Advice(通知):
- 前置通知(前置增强)before() :执行方法前通知
- 返回通知(返回增强)afterReturn:方法正常结束返回后的通知
- 异常抛出通知(异常抛出增强):afetrThrow()
- 最终通知 after:无论方法是否发生异常,均会执行该通知
- 环绕通知 around:包围一个连接点(joinpoint)的通知,如方法调用
- Aspect(切面):切入点和通知的抽象
- Target(目标对象):被代理的目标对象
- Weave(织入):将切面应用到目标对象并生成代理对象的这个过程
- Introduction(引入):在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程
2、Spring AOP 的实现
2.1、环境搭建
2.1.1、引入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
2.1.2、添加 spring.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
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 开启扫描 -->
<context:component-scan base-package="com.yjxxt"/>
<!-- 开启注解开发 aop -->
<aop:aspectj-autoproxy/>
</beans>
2.2、注解实现
2.2.1、类
public class User {
private Integer id;
private String name;
private String password;
public User() {}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
2.2.2、mapper 层
public interface UserDao {
public int insertUser(User user);
public int deleteUserById(Integer id);
public int updateUser(User user);
}
@Repository
public class UserDaoImpl implements UserDao {
@Override
public int insertUser(User user) {
System.out.println("insertUser.....");
return 1;
}
@Override
public int deleteUserById(Integer id) {
System.out.println("deleteUserById.....");
return 1;
}
@Override
public int updateUser(User user) {
System.out.println("updateUser.....");
return 1;
}
}
2.2.3、service 层
public interface UserService {
public int addUser(User user);
public int removeUserById(Integer id);
public int changeUser(User user);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
public UserDao userDao;
@Override
public int addUser(User user) {
System.out.println("UserService addUser.....");
return userDao.insertUser(user);
}
@Override
public int removeUserById(Integer id) {
return userDao.deleteUserById(id);
}
@Override
public int changeUser(User user) {
return userDao.updateUser(user);
}
}
2.2.4、controller
@Controller
public class UserController {
@Autowired
public UserService userService;
public void add(){
int i = userService.addUser(new User());
if (i == 1) {
System.out.println("添加成功!");
}
}
}
2.2.5、aop 层
@Component
@Aspect
public class LogerPage {
// 切点
@Pointcut(value = "execution(* com.yjxxt.service.UserServiceImpl.addUser(..))")
public void cut(){
}
@Before(value = "cut()")
public void addlog1(){
System.out.println(new Date().toLocaleString());
}
// 切面
@After(value = "execution(* com.yjxxt.service.UserServiceImpl.addUser(..))")
public void addlog2(){
System.out.println(new Date().toLocaleString());
}
}
2.2.6、测试
public class Test01 {
@Test
public void test01(){
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
UserController uc = app.getBean("userController", UserController.class);
uc.add();
}
}
2、代理模式
2.1、静态代理
2.1.1、静态代理的三要素:
-
有共同的行为 ——> 接口
-
目标角色 ——> 实现行为
-
代理角色 ——> 实现行为,增强目标对象行为
2.1.2、静态代理的特点
-
目标角色固定
-
在应用程序执行前就得到目标角色
-
代理对象会增强目标对象的行为
-
有可能存在多个代理引起 "类爆炸"(缺点)
2.1.3、静态代理的实现(需实现接口)
定义行为(接口)
public interface Marray {
public void toMarray();
}
目标对象
public class You implements Marray{
@Override
public void toMarray() {
System.out.println("我要结婚了!!!");
}
}
代理对象
public class CompProxy implements Marray {
// 目标对象
public Marray marray;
public CompProxy(Marray marray) {
this.marray = marray;
}
@Override
public void toMarray() {
// 前置增强
before();
// 调用目标对象的方法
marray.toMarray();
// 后置增强
after();
}
public void before(){
System.out.println("准备婚礼!!!");
}
public void after(){
System.out.println("洞房花烛!!!");
}
}
测试
public class Test01 {
@Test
public void test01(){
// 实例化目标对象
You you = new You();
// 实例化代理对象
CompProxy proxy = new CompProxy(you);
// 代理对象执行目标对象的方法
proxy.toMarray();
}
}
2.2、动态代理
2.2.1、动态代理的特点:
-
目标对象不固定
-
在应用程序执行时动态创建目标对象
-
代理对象会增强目标对象的行为
2.2.2、 JDK 动态代理(有接口实现)
public class JdkHanlder implements InvocationHandler {
// 目标对象
private Object target;
public JdkHanlder(Object target) {
this.target = target;
}
/**
* 调用目标对象的方法,增强目标对象的行为
* @param proxy 调用该方法的代理实例
* @param method 目标对象的方法
* @param args 目标对象的方法形参
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("before");
// 通过反射执行目标对象的方法
Object result = method.invoke(target, args);
// 后置增强
System.out.println("after");
return result;
}
/**
* 获取动态代理对象
* @return
*/
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
public class Test02 {
@Test
public void test02(){
// 实例化目标对象
You you = new You();
// 实例化代理对象
JdkHanlder jdkHanlder = new JdkHanlder(you);
// 动态的获取代理对象
Marray proxy = (Marray) jdkHanlder.getProxy();
// 代理对象执行目标对象的方法
proxy.toMarray();
}
}
2.2.3、CGLIB 动态代理
引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
定义类
public class User {
public void add(){
System.out.println("我要增强.....");
}
}
public class CglibProxy implements MethodInterceptor {
// 目标对象
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
/**
* 调用目标对象的方法,增强目标对象的行为
* @param o 由 CGLib 动态生成的代理实例
* @param method 实体类所调用的被代理的方法引用
* @param objects 参数值列表
* @param methodProxy 生成的代理类对方法的代理引用
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 前置增强
System.out.println("before");
// 通过反射执行目标对象的方法
Object result = methodProxy.invoke(target, objects);
// 后置增强
System.out.println("after");
return result;
}
public Object getProxy(){
// 实例化对象
Enhancer enhancer = new Enhancer();
// 将目标对象作为父类
enhancer.setSuperclass(target.getClass());
// 设置拦截器 回调对象为本身对象
enhancer.setCallback(this);
// 生成一个代理类对象,并返回
return enhancer.create();
}
}
public class Test03 {
@Test
public void test03(){
// 实例化目标对象
User user = new User();
// 实例化代理对象
CglibProxy cglibProxy = new CglibProxy(user);
// 动态的获取代理对象
User proxy = (User) cglibProxy.getProxy();
// 代理对象执行目标对象的方法
proxy.add();
}
}