AOP 代理模式
引入:
静态代理模式:
dao层
1-1-0 接口:UserDao
package com.kuang.w.demo02.dao;
public interface UserDao {
/**
* class add()
*/
void add();
/**
* class upTable
*/
void upTable();
}
1-1-1 实现接口 :UserDaoImpl
package com.kuang.w.demo02.dao;
public class UserDaoImpl implements UserDao {
public void add() {
System.out.println ("添加....");
}
public void upTable() {
System.out.println ("删除....");
}
}
service层
1-2-0 接口UserService
package com.kuang.w.demo02.service;
public interface UserService {
/**
* class add()
*/
void add();
/**
* class upsate
*/
void update();
}
1-2-1实现接口 UserServiceImpl
package com.kuang.w.demo02.service;
import com.kuang.w.demo02.dao.UserDao;
import com.kuang.w.demo02.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl ();
public void add() {
userDao.add ();
}
public void update() {
userDao.upTable ();
}
}
1-2-2实现接口 UserServiceImpl
这是一个增强功能 的实现接口 添加了一个日志功能
package com.kuang.w.demo02.service;
import com.kuang.w.demo02.dao.UserDao;
import java.lang.reflect.InvocationHandler;
public class UserServiceImplLog implements UserDao {
private UserServiceImpl userService = new UserServiceImpl ();
public void add() {
userService.add ();
log ("add");
}
public void upTable() {
userService.update ();
log ("up");
}
public void log(String name) {
System.out.println (" 调用了" + name + "方法!");
}
}
3测试:
public void t07() {
UserServiceImplLog implLog = new UserServiceImplLog ();
implLog.upTable ();
}
测试结果:
删除....
调用了up方法!
Process finished with exit code 0
动态代理(固定代码)
package com.kuang.w.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理 :用这个类自动生成代理类
*/
public class ProxyInvocationHandlerUtil implements InvocationHandler {
/**
* 被代理的接口
* Object target
*/
private Object target;
public void setTarget(Object target) {
this.target = target;
}
/**
* 生成代理类
*/
public Object getProxy() {
return Proxy.newProxyInstance (this.getClass ().getClassLoader (), target.getClass ().getInterfaces (), this);
}
/**
* 处理代理实例 并返回结果
* 执行被代理类的方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke (target, args);
log (method.getName ());
return invoke;
}
//这是一个添加的方法
private void log(String msg) {
System.out.println ("调用了" + msg + "方法");
}
}
测试:(引用了前面包在这里插入代码片
内的方法)
package com.kuang.w.demo03;
import com.kuang.w.demo02.service.UserService;
import com.kuang.w.demo02.service.UserServiceImpl;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import javax.annotation.Resource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl ();
//代理角色不存在 就创建
ProxyInvocationHandlerUtil pih = new ProxyInvocationHandlerUtil ();
//设置要代理的对象
pih.setTarget (userService);
//动态生成代理
UserService proxy = (UserService) pih.getProxy ();
proxy.update ();
}
}
使用spring方式 重点
AOP称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。
一 AOP的基本概念
(1)Aspect(切面):通常是一个类,里面可以定义切入点和通知
(2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用
(3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around
(4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式
(5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
二 Spring AOP
Spring中的AOP代理还是离不开Spring的IOC容器,代理的生成,管理及其依赖关系都是由IOC容器负责,Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。
maven配置加上:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一 使用原生的 spring API接口
package com.kuang.w.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MyLog01 implements MethodBeforeAdvice {
/**
* method 要执行的的目标对象的方法
* objects --- args 参数
* o --- target 目标对象
*/
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println (o.getClass ().getName () + "的" + method.getName () + "方法被执行了!");
}
}
第一种 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
bean标签 id唯一标识符 也就相当于我们 学的对象
class 对应对象的全限定名 包名 + 类型
name 也是别名 而且name 可以取多个别名 可以用 , ; 空格分隔
-->
<!--注册bean-->
<bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
<bean class="com.kuang.w.log.MyLog01" id="myLog"/>
<!--方式一 使用原生的 spring API接口-->
<!--绑定log 配置aop -->
<aop:config>
<!--切入点:execution:表达式 execution(要执行的位置! 修饰词 返回值 类名 方法名 参数)-->
<aop:pointcut id="poi" expression="execution(* com.kuang.w.service.UserServiceImpl.*(..))"/>
<!--执行环绕-->
<aop:advisor advice-ref="myLog" pointcut-ref="poi"/>
</aop:config>
</beans>
测试(3个代码都一样):
@Test
public void Test08() {
ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
UserService userService = context.getBean ("userService", UserService.class);
userService.update ();
}
}
测试结果:
com.kuang.w.service.UserServiceImpl的update方法被执行了!
修改方法
第二种方式 自定义( 推荐)
package com.kuang.w.log;
public class Log2 {
public void qw() {
System.out.println ("执行前");
}
public void hw() {
System.out.println ("执行后");
}
}
第二种 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
bean标签 id唯一标识符 也就相当于我们 学的对象
class 对应对象的全限定名 包名 + 类型
name 也是别名 而且name 可以取多个别名 可以用 , ; 空格分隔
-->
<!--注册bean-->
<bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
<bean class="com.kuang.w.log.MyLog01" id="myLog"/>
<bean class="com.kuang.w.log.Log2" id="log2"/>
<!-- 推荐-->
<!--第二种方式 自定义-->
<aop:config>
<!--自定义 切面-->
<aop:aspect ref="log2">
<!--切入点-->
<aop:pointcut id="poi" expression="execution(* com.kuang.w.service.UserServiceImpl.*(..))"/>
<aop:before method="qw" pointcut-ref="poi"/>
<aop:after method="hw" pointcut-ref="poi"/>
</aop:aspect>
</aop:config>
</beans>
测试结果:
执行前
修改方法
执行后
Process finished with exit code
第三种 java代码
package com.kuang.w.log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Log03 {
/**
* @Before 执行方法前
*/
@Before("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
public void before01() {
System.out.println ("执行前===");
}
/**
* @After 执行方法后
*/
@After("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
public void after() {
System.out.println ("执行后====");
}
/**
* 环绕注解 在一个方法执行时
*
* @Around
*/
@Around("execution(* com.kuang.w.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println ("方法执行前");
try {
Object proceed = joinPoint.proceed ();
} catch (Throwable throwable) {
throwable.printStackTrace ();
}
//获取签名
System.out.println ("调用了:" + joinPoint.getSignature () + "的方法,执行了");
System.out.println ("方法执行后");
}
}
第三种 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
bean标签 id唯一标识符 也就相当于我们 学的对象
class 对应对象的全限定名 包名 + 类型
name 也是别名 而且name 可以取多个别名 可以用 , ; 空格分隔
-->
<!--注册bean-->
<bean class="com.kuang.w.service.UserServiceImpl" id="userService"/>
<bean class="com.kuang.w.log.MyLog01" id="myLog"/>
<!--第三种 注解-->
<!--还是用bean注册-->
<bean class="com.kuang.w.log.Log03" id="log03"/>
<!--开启注解支持 实现方式:jdk(默认 expose-proxy="false") cglib(expose-proxy="true")-->
<aop:aspectj-autoproxy expose-proxy="true"/>
</beans>
测试:
@Test
public void Test08() {
ApplicationContext context = new ClassPathXmlApplicationContext ("beans.xml");
UserService userService = context.getBean ("userService", UserService.class);
userService.update ();
}
}
测试 第三种结果
方法执行前
执行前===
修改方法
执行后====
调用了:void com.kuang.w.service.UserService.update()的方法,执行了
方法执行后
Process finished with exit code 0