spring AOP对父类方法加强分析

spring AOP可以对方法进行加强,就是在方法前执行一些想要的事情,执行方法后想执行一些信息,原理就是利用动态代理,具体不在阐述
今天要讨论的是一个springBean继承了父类,在父类里进行了方法加强,子类调用父类的方法,父类方法会加强吗?
注解@CommonLogger是我利用AOP Aspect写的一个打印方法参数的注解,就是在方法上加了这个注解,这个方法的参数就会打印出来,并且对日志进行了脱敏处理

现在有以下父类

public  class LogFilterServiceParent {
		private Logger logger = LoggerFactory.getLogger(getClass());
	
		@CommonLogger(positions={Position.PARAMTER})
		public void log2(OrderDetailDTO dto,String str) {
		logger.info("--------------------------------LogFilterServiceParent---------------------------");
		}
}

子类

@Service
public class LogFilterServiceImpl extends LogFilterServiceParent implements LogFilterService {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public void log(OrderDetailDTO dto,String str) {
		this.log2(dto, str);
		logger.info("--------------------------------LogFilterServiceImpl---------------------------");
	}

}

public interface LogFilterService {
	void log(OrderDetailDTO dto,String str);
}

测试类

@RunWith(SpringJUnit4ClassRunner.class)//其他相关配置省去
public class LogFilterServiceTest extends BaseSARTest {
	@Autowired
	private LogFilterService logFilterService;
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Test
	public void testLogFilter() {
		OrderDetailDTO dto = new OrderDetailDTO();
		
		NbiCustomerInfoDTO custom = new NbiCustomerInfoDTO();
		custom.setBirthday("2016-02-25");
		custom.setDetailAddress("广东生深圳市罗湖区大剧院京基100大厦");
		custom.setEmail("[email protected]");
		custom.setCardId("440515199212237208");
		custom.setMobileNo("13698545691");
		custom.setName("张山疯");
		
		
		dto.setApplyPolicyNo("12365998");
		dto.setCurrentSysDate(new Date());
		dto.setOrderNo("AA201807130849120300010000001");
		dto.setPolicyHolder(custom);
		
		List list = new ArrayList();
		list.add(custom);
		list.add(custom1);
		dto.setCustomerInfoList(list);
		dto.setOrderStatus(2);
		logFilterService.log(dto,"440515199212237208");
	}
	
	
	
	
}

我想达到的效果是,LogFilterServiceImpl调用父类的log2方法,log2方法能够打印入参,但实际上没有打印,并且报了以下错误

[14:30:23.235] [DEBUG] [] AnnotationAwareAspectJAutoProxyCreator: Creating implicit proxy for bean 'logFilterServiceImpl' with 0 common interceptors and 2 specific interceptors
[14:30:23.235] [DEBUG] [] CglibAopProxy: Creating CGLIB proxy: target source is SingletonTargetSource for target object [com.shux.trade.online.service.LogFilterServiceImpl@456ce9]
[14:30:23.235] [DEBUG] [] CglibAopProxy: Unable to apply any optimisations to advised method: public void com.shux.trade.online.service.LogFilterServiceImpl.log(com.shux.trade.online.dto.OrderDetailDTO,java.lang.String)
[14:30:23.235] [DEBUG] [] CglibAopProxy: Unable to apply any optimisations to advised method: public void com.shux.trade.online.service.LogFilterServiceParent.log2(com.shux.trade.online.dto.OrderDetailDTO,java.lang.String)
[14:30:23.235] [DEBUG] [] CglibAopProxy: Found 'hashCode' method: public native int java.lang.Object.hashCode()
[14:30:23.235] [DEBUG] [] CglibAopProxy: Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
[14:30:23.235] [DEBUG] [] CglibAopProxy: Unable to apply any optimisations to advised method: protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException
[14:30:23.235] [DEBUG] [] CglibAopProxy: Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
[14:30:23.235] [DEBUG] [] CglibAopProxy: Found finalize() method - using NO_OVERRIDE
[14:30:23.235] [DEBUG] [] CglibAopProxy: Method is declared on Advised interface: public abstract void org.springframework.aop.framework.Advised.addAdvice(int,org.aopalliance.aop.Advice) throws org.springframework.aop.framework.AopConfigException

没懂这个报错的意思

按照继承的规则,子类自动拥有父类的方法,按理应该spring会给加了注解的方法加强,但实际上没有
查阅spring aop相关的内容,发现spring AOP不支持同类方法调用,意思就是同一个spring Bean中,如果多个方法中都用了方法加强,一个方法调用了另外一个方法,另外一个方法(被调用方法)是无法加强的,于是我改了一下
在子类的接口中增加父类的方法

public interface LogFilterService {
	void log(OrderDetailDTO dto,String str);
 void log2(OrderDetailDTO dto,String str);
}

测试类直接调用父类的这个方法log2,测试方法改成如下

@Test
	public void testLogFilter() {
		OrderDetailDTO dto = new OrderDetailDTO();
		
		NbiCustomerInfoDTO custom = new NbiCustomerInfoDTO();
		custom.setBirthday("2016-02-25");
		custom.setDetailAddress("广东生深圳市罗湖区大剧院京基100大厦");
		custom.setEmail("[email protected]");
		custom.setCardId("440515199212237208");
		custom.setMobileNo("13698545691");
		custom.setName("张山疯");
		
		
		dto.setApplyPolicyNo("12365998");
		dto.setCurrentSysDate(new Date());
		dto.setOrderNo("AA201807130849120300010000001");
		dto.setPolicyHolder(custom);
		
		List list = new ArrayList();
		list.add(custom);
		list.add(custom1);
		dto.setCustomerInfoList(list);
		dto.setOrderStatus(2);
		logFilterService.log2(dto,"440515199212237208");//这里有变化

	}

发现日志打印出来了,意思就是父类的方法加强起效了,然我又把带接口的方式放到方法log中,如下

@Service
public class LogFilterServiceImpl extends LogFilterServiceParent implements LogFilterService {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public void log(OrderDetailDTO dto,String str) {
		this.log2(dto, str);
		logger.info("--------------------------------LogFilterServiceImpl---------------------------");
	}

}

测试类

@Test
	public void testLogFilter() {
		OrderDetailDTO dto = new OrderDetailDTO();
		
		NbiCustomerInfoDTO custom = new NbiCustomerInfoDTO();
		custom.setBirthday("2016-02-25");
		custom.setDetailAddress("广东生深圳市罗湖区大剧院京基100大厦");
		custom.setEmail("[email protected]");
		custom.setCardId("440515199212237208");
		custom.setMobileNo("13698545691");
		custom.setName("张山疯");
		
		
		dto.setApplyPolicyNo("12365998");
		dto.setCurrentSysDate(new Date());
		dto.setOrderNo("AA201807130849120300010000001");
		dto.setPolicyHolder(custom);
		
		List list = new ArrayList();
		list.add(custom);
		list.add(custom1);
		dto.setCustomerInfoList(list);
		dto.setOrderStatus(2);
		logFilterService.log(dto,"440515199212237208");//这里有变化

	}

发现还是不能打印日志,正对这种情况我又百度了一下,要使调用本类的方法并且是方法加强有效,则必须使用以下方式
在spring配置文件中,aop:aspectj-autoproxy 标签增加expose-proxy="true"属性,如下配置

 

public  class LogFilterServiceParent {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@CommonLogger(positions={Position.PARAMTER})
	public void log2(OrderDetailDTO dto,String str) {
		//logger.debug(sensitivityMessageFilter.doSensitivityFilter(dto));
		logger.info("--------------------------------LogFilterServiceParent---------------------------");
	}
}

然后子类调用父类的log2方法用以下方式调用

public void log(OrderDetailDTO dto,String str) {
		((LogFilterServiceImpl)AopContext.currentProxy()).log2(dto, str);
		logger.info("--------------------------------LogFilterServiceImpl---------------------------");
}

然后在调用测试类

@Test
	public void testLogFilter() {
		OrderDetailDTO dto = new OrderDetailDTO();
		
		NbiCustomerInfoDTO custom = new NbiCustomerInfoDTO();
		custom.setBirthday("2016-02-25");
		custom.setDetailAddress("广东生深圳市罗湖区大剧院京基100大厦");
		custom.setEmail("[email protected]");
		custom.setCardId("440515199212237208");
		custom.setMobileNo("13698545691");
		custom.setName("张山疯");
		
		
		dto.setApplyPolicyNo("12365998");
		dto.setCurrentSysDate(new Date());
		dto.setOrderNo("AA201807130849120300010000001");
		dto.setPolicyHolder(custom);
		
		List list = new ArrayList();
		list.add(custom);
		list.add(custom1);
		dto.setCustomerInfoList(list);
		dto.setOrderStatus(2);
		logFilterService.log(dto,"440515199212237208");//这里有变化

	}

发现可以打印日志了
the params of com.shux.trade.online.service.LogFilterServiceParent.log2 is :dto:{"orderNo":"IC201807130849120300010000001","currentSysDate":1547541805585,"policyHolder":{"cardId":"4****************8","birthday":"******","email":"******@qq.com","name":"*山疯","mobileNo":"1369****691","sortNumber":0,"detailAddress":"广东生深圳市罗湖区******"},"orderStatus":2,"customerInfoList":[{"cardId":"4****************8","birthday":"******","email":"******@qq.com","name":"*山疯","sortNumber":0,"mobileNo":"1369****691","detailAddress":"广东生深圳市罗湖区******"},{"cardId":"4****************8","birthday":"******","email":"******@qq.com","name":"*山疯","sortNumber":0,"mobileNo":"1332****424","detailAddress":"广东生深圳市罗湖区******"}],"applyPolicyNo":"12365998"},str:"4****************8"

为什么会这样?为什么直接掉没有用
其实这个也很简单,大家都知道spring的AOP其实是动态代理,没有走AOP加强说明了没有走代理,根据spring的springBean自动注入和动态代理
自动注入的都是其他类,自己是不会注入到自己本类的,自然就没有自动注入代理类了,自己掉自己没有走代理,自然就不会有加强了
为了解决这种问题,spring提供了AopContext类。
到时这样做会比较麻烦,大师们有更好的办法吗?

你可能感兴趣的:(Spring)