简单实例
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <context:property-placeholder location="classpath*:*.properties"/>-->
<context:component-scan base-package="li.dongpo.tc" />
<bean id="sampleServiceImpl" class="li.dongpo.tc.service.SampleServiceImpl" />
<bean id="sampleBeanPostProcessor" class="li.dongpo.tc.service.SampleBeanPostProcessor" />
</beans>
public class Application {
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
SampleService sampleService0 = (SampleService) context.getBean("sampleServiceImpl");
sampleService0.hello();
SampleService sampleService1 = context.getBean(SampleService.class);
sampleService1.hello();
}
}
package li.dongpo.tc.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* dongpo.li
* 2020/5/18
*/
public class SampleBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName);
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy1, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object result = method.invoke(bean, args);
System.out.println(bean.getClass().getName() + "#" + method.getName() + "执行时间" + (System.currentTimeMillis() - start));
return result;
}
});
return proxy;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
package li.dongpo.tc.service;
/**
* dongpo.li
* 2020/5/18
*/
public interface SampleService {
void hello();
}
package li.dongpo.tc.service;
/**
* User: dongpo.li
* Date: 2020-05-14
*/
public class SampleServiceImpl implements SampleService {
public void hello() {
System.out.println("hello world");
}
}
其中SampleBeanPostProcessor就是我们自定义的BeanPostProcessor,它使用Spring的后置处理器,在实例创建结束之后,将该bean的动态代理作为bean的实例存入IoC容器中,这样,之后调用这个bean的所有方法都会打印执行时间.
实例的代码执行结果:
sampleServiceImpl
hello world
li.dongpo.tc.service.SampleServiceImpl#hello执行时间0
hello world
li.dongpo.tc.service.SampleServiceImpl#hello执行时间0
注意有坑
这样处理之后,IoC容器中的bean是SampleServiceImpl的一个代理类,由于使用JDK动态代理,所以它是接口SampleService的另一个实现,此时,如果还是直接使用SampleServiceImpl接收的话,是会有问题的.
// 抛ClassCastException
SampleServiceImpl sampleService0 = (SampleServiceImpl) context.getBean("sampleServiceImpl");
// 抛NoSuchBeanDefinitionException
SampleServiceImpl sampleService1 = context.getBean(SampleServiceImpl.class);
感兴趣的话可以试一下.
这样本来是没有问题的,依赖反转要求就是依赖抽象而不是依赖具体实现,但是在感性上,IoC容器里应该是SampleServiceImpl的一个实例,因为xml中就是这样配置的,而且目前笔者很少见到有项目严格遵守这个规范.所以不明白其中的原理或者不知道有这个后置处理器的时候,问题就很难排查了,需要注意一下.