代理
SpringAOP和SpringMVC
Proxy,InvocationHandler
动态代理分为:
- 基于接口的动态代理:JDK
- 基于类的动态代理:cglib
public interface MyInterface {
public void interfaceFun();
}
public class MyInterfaceImpl implements MyInterface{
@Override
public void interfaceFun() {
System.out.println("接口方法");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target, args);
return result;
}
}
public class MyClient {
public static void main(String[] args) {
MyInterfaceImpl impl = new MyInterfaceImpl();
MyInvocationHandler mih = new MyInvocationHandler();
mih.setTarget(impl);
MyInterface myInterface = (MyInterface) mih.getProxy();
myInterface.interfaceFun();
}
}
AOP
思想:在不影响原有业务逻辑的前提下,实现业务的横向扩展
方法一:使用Spring的API接口,需要接口类,实现类,日志类
在接口方法前后添加切片日志:
接口类:
public interface ServiceInterface {
public void add();
public void del();
public void select();
public void update();
}
接口实现类:
public class ServiceImpl implements ServiceInterface{
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void del() {
System.out.println("删除一个用户");
}
@Override
public void select() {
System.out.println("查询用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
}
日志类:
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
Spring:
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="serviceImpl" class="org.example.service.ServiceImpl"/>
<bean id="log" class="org.example.log.Log"/>
<!-- 方式一:使用SpringAPI接口 -->
<aop:config>
<!-- 切入点 -->
<!-- execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))
修饰符默认为public可省略
(..) 代表所有参数-->
<aop:pointcut id="pointcut"
expression="execution(* org.example.service.ServiceImpl.*(..))"/>
<!-- 执行环绕 -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
</aop:config>
</beans>
完成
方法二:自定义实现
自定义日志类:
public class Diy {
public void after() {
System.out.println("-----方法执行后-----");
}
public void before() {
System.out.println("-----方法执行前-----");
}
}
Spring:
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="serviceImpl" class="org.example.service.ServiceImpl"/>
<bean id="log" class="org.example.log.Log"/>
<!-- 方式二 -->
<bean id="diy" class="org.example.log.Diy"/>
<aop:config>
<!-- 自定义切面 -->
<aop:aspect ref="diy">
<!-- 切入点 -->
<aop:pointcut id="point"
expression="execution(* org.example.service.ServiceImpl.*(..))"/>
<!-- 通知 -->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
方式三:使用注解实现
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 MyDiy {
@Before("execution(* org.example.service.ServiceImpl.*(..))")
public void before() {
System.out.println("=====方法执行前=====");
}
@After("execution(* org.example.service.ServiceImpl.*(..))")
public void after() {
System.out.println("=====方法执行后=====");
}
@Around("execution(* org.example.service.ServiceImpl.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
//pjp可以看作是方法本身
System.out.println("方法执行前");
System.out.println(pjp.getSignature());
pjp.proceed();
System.out.println("方法执行后");
}
}
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="serviceImpl" class="org.example.service.ServiceImpl"/>
<bean id="log" class="org.example.log.Log"/>
<!-- 方式三 -->
<bean id="myDiy" class="org.example.log.MyDiy"/>
<!-- 开启注解支持 -->
<aop:aspectj-autoproxy/>
</beans>