AOP:面向切面编程AOP思想
Aspect 切面:功能模块切入多个类中
@Aspect:有此注解就一定要托管@Component
Join Point 连接点:预测表达式Pointcut 切入点:新功能切入的点Advice 行为:切入点上的行为,即新功能Target object 目标类:待增强功能的类AOP proxy 代理类:目标类+切面生成的一个新类,实际调用的也是该类中的方法
使用前导入jar包
2.AOP使用org.aspectj aspectjweaver 1.9.8
代理类(配置类) @EnableAspectJAutoProxy
@EnableAspectJAutoProxy:自动检测@Aspect
-->相当于代理类中扫描切面类
--------------------------------------------------------------
@Configuration
@ComponentScan(basePackages = "com.yc.bean")
@EnableAspectJAutoProxy
public class AppConfig {
@Bean
public Random r() {
return new Random();
}
}
切面类 @Aspect
1.@Aspect:表明这是一个切面类
2.@Pointcut("execution(* transfer(..))"):切入点表达式(5.4.3)
-->在方法上
-->execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)
-->0或1个修饰符,返回值类型,0或1个声明类型模式,方法模式(参数模式),抛出异常模式
3.@Before/@Around/..:切入点位置
-->@Before:前置增强
默认顺序根据方法名,@Order(1)可以设置切面类的优先级,也可以实现接口Ordered
-->@Around:环绕增强(方法有一部分先执行,一部分后执行)
高优先级进去先,后出来
返回值Object,参数ProceedingJoinPoint
--------------------------------------------------------------
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(* com.yc.bean.Container.add(..))")
private void a() { }
@Before("com.yc.bean.MyAspect.a()")//切入点位置
public void log(JoinPoint jp) {//JoinPoint实际是一个接口,该对象在调用时以di方式注入
Date date = new Date();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = df.format(date);
System.out.println("当前执行的时间:" + time);
Object target = jp.getTarget();//取出目标类
Object proxy = jp.getThis();//取出代理类
Object[] params = jp.getArgs();//取出参数
}
@Around("a()")
public Object runtime(ProceedingJoinPoint pjp) {//ProceedingJoinPoint环绕增强时使用,必须要该参数
long starttime = System.currentTimeMillis();
Object returnValue = null;
try {
returnValue = pjp.proceed();//运行该连接点
} catch (Throwable throwable) {
throwable.printStackTrace();
}
long endtime = System.currentTimeMillis();
System.out.println("程序运行时间:" + (endtime - starttime));
return returnValue;//必须要用该返回值(连接点方法的返回值)
}
}
3.合并切入点
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")//某包下的所有public方法
private void tradingOperation() {}
4.代理机制
静态代理:只能代理一个确定的类动态代理:任意的目标类都可以代理JDK 面向接口
1.回调器:实现InvocationHandler接口,定义目标target类,目标类是一个接口实现类
public class CustomInvocationHandler implements InvocationHandler {
private Object target;//目标类引用
public CustomInvocationHandler(Object target) {this.target = target;}
//生成代理对象,代理接口中所有方法
//(类加载器/字节码加载器,目标类所有接口,激活时的回调处理器)
public Object createInstance() {
return Proxy.newProxyInstance(CustomInvocationHandler.class.getClassLoader(),
target.getClass().getInterfaces(), this);
}
//实现一个接口 对目标类生成代理对象
//感知到客户端调用被代理的方法,自动回调invoke(),激活对应方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equalsIgnoreCase("sayHello")) {
System.out.println("Before invocation");//升级成切入点表达式
}
Object retVal = method.invoke(target, args);
//相当于调用了目标类的sayHello() target.method(args)
System.out.println("After invocation");
return retVal;
}
}
2.Hello接口
public interface Hello {
public void sayHello(String name);
public void bye();
}
3.HelloImpl接口实现类
public class HelloImpl implements Hello {
@Override
public void sayHello(String name) {
System.out.println("Hello:" + name);
}
@Override
public void bye() {
System.out.println("bye");
}
}
4.测试类
public class TestMain {
public static void main(String[] args) {
//保存生成的字节码文件 com.sun... -->为源码解读做准备
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
CustomInvocationHandler handler = new CustomInvocationHandler(new HelloImpl());
//生成代理类对象 $Proxy -->生成字节码的时机:运行期由jdk动态代理来生成字节码,编译块,运行慢(动态代理机制)
Hello proxy = (Hello) handler.createInstance();
//自动激活invoke
proxy.sayHello("hhhh");//$proxy0.sayHello()
proxy.bye();
}
}
JDKProxy源码解读CGLIB 面向继承
1.使用前导入jar包2.方法拦截器:实现MethodInterceptor接口,定义目标target类 public class MyInterceptor implements MethodInterceptor { //生成代理对象 public Enhancer enhancer = new Enhancer(); //目标对象 private Object target; public MyInterceptor(Object target) {this.target = target;} //获取一个代理对象 public Object createInstance() { enhancer.setSuperclass(this.target.getClass()); //设置被代理方法时的回调 enhancer.setCallback(this); //生成代理对象 return enhancer.create(); } //自动回调 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if (method.getName().equalsIgnoreCase("sayHello")) { System.out.println("Before invocation");//升级成切入点表达式 } //目标方法 Object result = methodProxy.invokeSuper(target, objects); //相当于调用了目标类的sayHello() target.method(args) System.out.println("After invocation"); return result; } } 3.HelloImpl:未实现接口 public class HelloImpl { public void sayHello(String name) { System.out.println("Hello:" + name); } public void bye() { System.out.println("bye"); } } 4.测试类 public class TestMain { public static void main(String[] args) { //保存生成的字节码文件 com.sun... System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); CustomInvocationHandler handler = new CustomInvocationHandler(new HelloImpl()); Hello proxy = (Hello) handler.createInstance(); proxy.sayHello("hhhh"); proxy.bye(); } } cglib cglib 3.3.0



