AOP(Aspect Oriented Programming)面向切面编程
采用横向抽取机制,取代了传统纵向继承体系重复性代码
Spring AOP使用纯java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类织入增强代码
1、jdk的动态代理
2、cglib的动态代理
1、新建接口UserDao
public interface UserDao {
public void save();
public void update();
public void delete();
public void find();
}
2、新建UserDao实现类UserDaoImpl。这里不做过多操作,只打印输出相关信息
public class UserDaoImpl implements UserDao{
@Override
public void save() {
System.out.println("保存用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void find() {
System.out.println("查询用户");
}
}
3、新建一个代理类做增强操作
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyJdkProxy implements InvocationHandler {
private UserDao userDao;
public MyJdkProxy(UserDao userDao){
this.userDao = userDao;
}
public Object createProxy(){
Object proxy = Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
return proxy;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//判断如果为save方法则进行数据校验
if ("save".equals(method.getName())){
System.out.println("权限校验....");
return method.invoke(userDao,args);
}
return method.invoke(userDao,args);
}
}
4、测试
@Test
public void demo1(){
UserDao userDao = new UserDaoImpl();
UserDao proxy = (UserDao) new MyJdkProxy(userDao).createProxy();
proxy.save();
proxy.update();
}
1、新建ProductDao类
public class ProductDao {
public void save(){
System.out.println("保存商品");
}
public void update(){
System.out.println("修改商品");
}
public void delete(){
System.out.println("删除商品");
}
public void find(){
System.out.println("查询商品");
}
}
2、创建代理类MyCglibProxy
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyCglibProxy implements MethodInterceptor {
public ProductDao productDao;
public MyCglibProxy(ProductDao productDao){
this.productDao = productDao;
}
public Object createProxy(){
//1、创建核心类
Enhancer enhancer = new Enhancer();
//2、设置父类
enhancer.setSuperclass(productDao.getClass());
//3、设置回调
enhancer.setCallback(this);
//4、生成代理
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("save".equals(method.getName())){
System.out.println("权限校验");
return methodProxy.invokeSuper(proxy,args);
}
return methodProxy.invokeSuper(proxy,args);
}
}
3、测试
@Test
public void demo1(){
ProductDao productDao = new ProductDao();
ProductDao proxy = (ProductDao) new MyCglibProxy(productDao).createProxy();
proxy.save();
proxy.update();
proxy.delete();
proxy.find();
}
代理知识总结:
Spring AOP增强类型
首先导入jar
public interface StudentDao {
public void find();
public void update();
public void save();
public void delete();
}
2、新建StudentDao实现类StudentDaoImpl
public class StudentDaoImpl implements StudentDao {
public void find() {
System.out.println("查询学生");
}
public void update() {
System.out.println("修改学生");
}
public void save() {
System.out.println("保存学生");
}
public void delete() {
System.out.println("删除学生");
}
}
3、新建增强类MybeforeAdvice并实现MethBeforeAdvice
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MybeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("这是前置增强(通知)");
}
}
4、配置文件配置
5、测试
@Test
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext2.xml");
//StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDao");
StudentDao studentDao = (StudentDao) applicationContext.getBean("studentDaoProxy");
studentDao.save();
studentDao.update();
studentDao.delete();
studentDao.find();
}
配置文件中的属性配置
总结
使用普通Advice 作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用 带有切点的切面
常用PointcutAdvisor实现类
1、新建CustomerDao
public class CustomerDao {
public void find(){
System.out.println("查询客户");
}
public void save(){
System.out.println("保存客户");
}
public void update(){
System.out.println("修改客户");
}
public void delete(){
System.out.println("删除客户");
}
}
2、新建MyAroundAdvice类继承MethodInterceptor,环绕增强
public class MyAroundAdvice implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("环绕前增强");
//执行目标方法
Object obj = invocation.proceed();
System.out.println("环绕后增强");
return obj;
}
}
3、配置文件
4、测试
@Test
public void demo1(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext3.xml");
//CustomerDao customerDao = (CustomerDao) applicationContext.getBean("customerDao");
CustomerDao customerDao = (CustomerDao) applicationContext.getBean("customerDaoProxy");
customerDao.save();
customerDao.update();
customerDao.delete();
customerDao.find();
}
前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大
解决办法:自动创建代理
详见下篇