代理模式创建代理对象,让代理对象控制目标对象的访问,并且可以在不改变目标对象的情况下添加一些额外的功能
不破坏原来代码的业务逻辑结构
代理对象与被代理对象必须实现同一接口,在代理对象中实现日志
public class UserServiceImpl implements UserService {
public boolean login(String name, String password){
if(name.equals("adi") && password.equals("123")){
System.out.println("业务逻辑:用户adi登录成功");
return true;
}else{
System.out.println("业务逻辑:用户adi登录失败");
return false;
}
}
}
package staticproxy;
import java.util.Date;
public class UserServiceStaticProxy implements UserService {
private UserService userService;
public UserServiceStaticProxy(UserService userService) {
this.userService = userService;
}
@Override
public boolean login(String name, String password) {
boolean isLogin = userService.login(name, password);
System.out.println("日志:" + name + "于" + new Date().toLocaleString() + "登录");
return isLogin;
}
}
UserServiceStaticProxy proxy = new UserServiceStaticProxy(new UserServiceImpl());
proxy.login("xxx","xxx");
InvocationHandler
接口,invoke()
方法,Proxy.newProxyInstance()
静态方法建立一个代理类对象(必须告知要代理的接口public class LoggerHandler implements InvocationHandler {
private Object delegate;
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("方法名是:"+method.getName());
result = method.invoke(delegate, args);
System.out.println("日志:" + args[0] + "于" + new Date().toLocaleString() + "登录");
return result;
}
}
LoggerHandler lh = new LoggerHandler();
UserService us = (UserService) lh.bind(new UserServiceImpl());
us.login("adi", "123");
独立于Spring框架,但Spring实现了AOP。
MethodBeforeAdvice
接口public class Md5Advice implements MethodBeforeAdvice {
@Override
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
System.out.println(arg0.getName());
System.out.println(arg1[1]);
System.out.println(arg2.getClass().getName());
String newPwd = Md5Encode.getMD5(arg1[1].toString().getBytes());
arg1[1] = newPwd;
}
}
AfterReturningAdvice
接口public class LogAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
System.out.println(arg0);
System.out.println(arg3);
System.out.println(arg2[0]+"在"+new Date().toLocaleString()+"登录");
arg0=false;
}
}
MethodInterceptor
接口也可决定方法是否执行。
public class TimeAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("方法开始执行时间:"+new Date().toLocaleString());
Object result = arg0.proceed();
System.out.println("方法结束执行时间:"+new Date().toLocaleString());
return result;
}
}
ThrowsAdvice
接口public class RegistExceptionAdvice implements ThrowsAdvice {
public void afterThrowing(Exception e) {
System.out.println("异常通知发生异常"+e.getMessage());
}
}
<!--注入代理的接口-->
<!--注入通知,list配置-->
<!--注入代理目标-->
<bean>
<bean id="UserProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.user.UserService"></property>
<property name="interceptorNames">
<list>
<value>Md5Advice</value>
<value>TimeAdvice</value>
</list>
</property>
<property name="target" ref="UserServiceImpl"></property>
</bean>
</beans>
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
//接口获取代理对象
UserService us = (UserService)ctx.getBean("UserProxy");
us.regist("adi", "123");
boolean bool = us.login("adi", "123");
System.out.println(bool);
public class MyAdvice {
public void before(JoinPoint joinPoint) {
System.out.println("前置通知");
}
//参数和配置名一致
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("后置通知");
}
public void after(JoinPoint joinPoint) {
System.out.println("最终通知");
}
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知");
Object[] args = joinPoint.getArgs();
Object result = null;
try {
result = joinPoint.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知");
return result;
}
public void throwMethod(Exception ex) {
System.out.println("异常通知");
}
}
<aop:config>
<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-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
">
<!-- 业务逻辑 -->
<bean id="UserServiceImpl" class="com.user.UserServiceImpl"></bean>
<!-- advices -->
<bean id="MyAdvice" class="com.advices.MyAdvice"></bean>
<aop:config>
<!--
定义切点
<aop:pointcut expression="execution(* com.user.*.*(..))" id="mypc"/>
切面
<aop:aspect id="MyAspect" ref="MyAdvice" order="2">
通知
<aop:before method="before" pointcut-ref="mypc"/>
</aop:aspect>
-->
<aop:aspect id="MyAspect" ref="MyAdvice" order="2">
<aop:before method="before" pointcut="execution(* com.user.*.*(..))" />
<aop:after-returning method="afterReturning" pointcut="execution(* com.user.*.*(..))" returning="result"/>
<aop:around method="around" pointcut="execution(* com.user.*.*(..))" />
<!--aop:after-throwing method="throwExMethod" pointcut="execution(* service.*.*(..))" throwing="ex"/-->
<aop:after method="after" pointcut="execution(* com.user.*.*(..))" />
</aop:aspect>
</aop:config>
</beans>
前置通知
环绕通知
业务执行....
最终通知
环绕通知
后置通知
<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-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
">
<aop:aspectj-autoproxy />
<context:annotation-config />
<context:component-scan base-package="com" />
</beans>
@Component
@Aspect
public class MyAdvice {
// @Before("execution(* com.user.*.*(..))")
public void before(JoinPoint joinPoint) {
System.out.println("前置通知");
}
// @AfterReturning(pointcut = "execution(* com.user.UserServiceImpl.*(..))", returning="result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("后置通知");
}
// @After("execution(* com.user.*.*(..))")
public void after(JoinPoint joinPoint) {
System.out.println("最终通知");
}
@Around("execution(* com.user.*.*(..))")
public Object around(ProceedingJoinPoint joinPoint) {
System.out.println("环绕通知");
Object[] args = joinPoint.getArgs();
Object result = null;
try {
result = joinPoint.proceed(args);
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕通知");
return result;
}
// @AfterThrowing(value = "execution(* com.user.*.*(..))", throwing="ex")
public void throwMethod(Exception ex) {
System.out.println("异常通知");
}
}
环绕通知
前置通知
业务执行,登录成功
环绕通知
最终通知
后置通知
后置通知如果出现异常,无法返回数据时,后置通知无法执行,但是最终通知可以执行。
不管有没有异常,最终通知一定执行,
没有异常,返回值正常时,后置通知才执行。
proxy 代理
Invocation 求助,调用
Handler 组织者、操作者
pointcut 切点
原文:https://www.cnblogs.com/occlive/p/13558853.html