AOP的概念:
Aspect Oriented Progr amming (面向切面编程)
可配置AOP框架实现
AOP使用场景
AOP用来封装横切关注点,具体可以在下面的场景中使用:
权限
缓存
错误处理
调试
记录跟踪
持久化
同步
事务
等等。
代码示例:
通过动态代理来生成代理对象,通过反射内省获取实现对象装配
类清单
测试类
package com.aop;
import org.junit.jupiter.api.Test;
import java.io.InputStream;
public class AopDemo {
@Test
public void aopDemo(){
//读取配置文件
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/aop/bean.properties");
//装配,创建bean的对象
BeanFactory beanFactory = new BeanFactory(in);
//获取代理对象
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)beanFactory.getBean("bean");
IManager proxy = (IManager)proxyFactoryBean.getProxy();
proxy.add("打不死的强子");
}
}
主业务接口:
做一个添加功能
package com.aop;
public interface IManager {
public void add(String item);
}
主业务的实现类
package com.aop;
import java.util.ArrayList;
import java.util.List;
public class IManagerImpl implements IManager {
List<String> list = new ArrayList<>();
@Override
public void add(String item) {
list.add(item);
System.out.println(item);
}
}
代理工作接口
package com.aop;
public interface Advice {
public void beforeAdvice();
public void afterAdvice();
}
代理工作的实现类
package com.aop;
//切面实现类
public class AdviceImpl implements Advice {
@Override
public void beforeAdvice() {
System.out.println("start time"+System.currentTimeMillis());
}
@Override
public void afterAdvice() {
System.out.println("end time"+System.currentTimeMillis());
}
}
配置文件信息
bean.target = com.aop.IManagerImpl
bean.advice = com.aop.AdviceImpl
bean = com.aop.ProxyFactoryBean
用于动态生成代理对象
package com.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactoryBean implements InvocationHandler {
private Advice advice;
private Object target;//目标对象
创建代理对象,参数为类加载器,对象所在类的接口
public Object getProxy(){
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
return proxy;
}
//代理对象要执行的方法
//proxy:代理对象
//method:被代理要执行的方法
//args:被代理对象的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.beforeAdvice();
Object invoke = method.invoke(target, args);
advice.afterAdvice();
return null;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}
用于组装bean信息
package com.aop;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class BeanFactory {
Properties pro = new Properties();
//构造方法实现文件加载
public BeanFactory(InputStream in) {
try {
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取一个Bean
public Object getBean(String name){
//从文件中得到bean name
String beanName = pro.getProperty(name);
Object bean = null;
try {
//通过beanname获取类信息
Class<?> aClass = Class.forName(beanName);
//实例化对象
bean = aClass.newInstance();
//获取两个类对应的类信息
Object target = Class.forName(pro.getProperty(name + ".target")).newInstance();
Object advice = Class.forName(pro.getProperty(name + ".advice")).newInstance();
//通过bean类信息得到类描述
BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
//得到类属性描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
//遍历属性描述器调用对应的属性对其设置set方法
for (int i = 0; i <propertyDescriptors.length ; i++) {
String propertyname = propertyDescriptors[i].getName();
Method writeMethod = propertyDescriptors[i].getWriteMethod();
if("target".equals(propertyname)){
writeMethod.invoke(bean,target);
}else if("advice".equals(propertyname)){
writeMethod.invoke(bean,advice);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return bean;
}
}