BeanFactory与ApplicationContext的区别与联系
BeanFactory是ApplicationContext的父接口。ApplicationContext 实现都 [组合]了BeanFactory的功能。
ApplicationContext 比 BeanFactory 多实现了四个接口:
MessageSource: 国际化功能,支持多种语言
ResourcePatternResolver: 通配符匹配资源路径
EnvironmentCapable: 环境信息,系统环境变量,.properties、.application.yml等配置文件中的值
ApplicationEventPublisher: 发布事件对象
SpringBoot的run方法返回ConfigurableApplicationContext
ConfigurableApplicationContext 返回的beanFactory是DefaultListableBeanFactory类,其中获取单例对象的方法是由DefaultSingletonBeanFactory的成员变量singletonObjects获取的。
MessageSource
根据不同的语言配置文件,读取不同的语言信息
在resources目录下创建四个文件messages.propertes、messages_en.properties、messages_ja.properties、messages_zh.properties,然后分别在四个文件里面定义同名的key,比如在message_en.properties中定义hi=hello,在messages_ja.propertes中定义hi=こんにちは,在messages_zh中定义hi=你好,这样在代码中就可以根据这个key hi和不同的语言类型获取不同的value了。
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.JAPANESE));
ResourcePatternResolver
获取类路径下的配置文件
Resource[] resources = context.getResources("classpath:messages*.properties");
for (Resource resource : resources) {
System.out.println(resource);
}
EnvironmentCapable
获取系统环境变量中的java_home和项目的application.yml中的server.port属性
System.out.println(context.getEnvironment().getProperty("java_home"));
System.out.println(context.getEnvironment().getProperty("server.port"));
ApplicationEventPublisher
发布监听事件
定义一个用户注册事件类,继承自ApplicationEvent类
public class UserRegisteredEvent extends ApplicationEvent {
public UserRegisteredEvent(Object source) {
super(source);
}
}
再定义一个监听器类,用于监听用户注册事件,类头上需要加@Component注解,将该类交给spring管理,定义一个处理事件的方法,参数类型为用户注册事件类的对象,方法头上需要加上@EventListener注解
@Component
@Slf4j
public class UserRegisteredListener {
@EventListener
public void userRegist(UserRegisteredEvent event) {
System.out.println("UserRegisteredEvent...");
log.debug("{}", event);
}
}
接着再定义一个用户服务类,里面有个register(String username, String password)方法可以完成用户的注册,注册完毕后发布一下用户注册完毕事件。
@Component
@Slf4j
public class UserService {
@Autowired
private ApplicationEventPublisher context;
public void register(String username, String password) {
log.debug("新用户注册,账号:" + username + ",密码:" + password);
context.publishEvent(new UserRegisteredEvent(this));
}
}
最后在Springboot启动类中调用一下UserService里面的register()方法注册一个新用户,UserRegisteredListener中就能处理这个用户注册完毕的事件,实现了UserService类和UserRegisteredListener类的解耦。
UserService userService = context.getBean(UserService.class);
userService.register("张三", "123456");
BeanFactory 实现类
DefaultListableBeanFactory
创建Bean的过程:
1.Bean的定义
// bean 的定义(即bean的一些描述信息,包含class:bean是哪个类,scope:单例还是多例,初始化、销毁方法等)
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
2.注册Bean
beanFactory.registerBeanDefinition("config", beanDefinition);
3.添加后处理器
// 给 BeanFactory添加一些常用的后处理器,让它具备解析@Configuration、@Bean等注解的能力
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
4.执行bean工厂后处理器:@Configuration;@Bean
// 从bean工厂中取出BeanFactory的后处理器,并且执行这些后处理器
// BeanFactory 后处理器主要功能,补充了一些 bean 的定义 beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values()
.forEach(beanFactoryPostProcessor -> {
System.out.println(beanFactoryPostProcessor);
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
5.执行Bean处理器:@Autowired;@Resource
beanFactory.addBeanPostProcessors(beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().sorted(beanFactory.getDependencyComparator())
.collect(Collectors.toCollection(ArrayList::new)));
@Autowired{类型};@Resource{名字}执行顺序
排序的依据是BeanPostProcessor内部的order属性
@Autowired
@Resource(name = "bean4")
private Inter bean3;
注入的是bean3,说明@Autowired生效
6.默认是延迟单例对象,使用它的时候才会进行构造创建对象实例
// 准备好所有单例,get()前就把对象初始化好
beanFactory.preInstantiateSingletons();
ApplicationContext接口的实现类
ClassPathXmlApplicationContext
//1.最为经典的容器,基于classpath 下 xml 格式的配置文件来创建
public void testClassPathXmlApplicationContext() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("spring_bean.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
FileSystemXmlApplicationContext
//2.基于磁盘路径下 xml 格式的配置文件来创建
public void testFileSystemXmlApplicationContext() {
// 可以用绝对路径或者相对路径
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src\\main\\resources\\spring_bean.xml");
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
ClassPathXmlApplicationContext和FileSystemXmlApplicationContext底层原理
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(
new FileSystemResource("src\\main\\resources\\spring_bean.xml"));
AnnotationConfigApplicationContext
//3.较为经典的容器,基于java配置类来创建
public void testAnnotationConfigApplicationContext() {
// 会自动加上5个后处理器
// org.springframework.context.annotation.internalConfigurationAnnotationProcessor
// org.springframework.context.annotation.internalAutowiredAnnotationProcessor
// org.springframework.context.annotation.internalCommonAnnotationProcessor
// org.springframework.context.event.internalEventListenerProcessor
// org.springframework.context.event.internalEventListenerFactory
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
System.out.println(context.getBean(Bean2.class).getBean1());
}
AnnotationConfigServletWebServerApplication
//4.较为经典的容器,基于java配置类来创建,并且还可以用于web环境
// 模拟了 springboot web项目内嵌Tomcat的工作原理
public void testAnnotationConfigServletWebServerApplicationContext() throws IOException {
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
// 防止程序终止
System.in.read();
}
}
@Configuration
class WebConfig {
@Bean
// 1. WebServer工厂
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
@Bean
// 2. web项目必备的DispatcherServlet
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}
@Bean
// 3. 将DispatcherServlet注册到WebServer上
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
return (request, response) -> {
response.getWriter().println("hello");
return null;
};
}
}
Bean的生命周期
@Component
@Slf4j
public class LifeCycleBean {
public LifeCycleBean() {
log.debug("构造");
}
@Autowired
public void autowire(@Value("${JAVA_HOME}") String name) {
log.debug("依赖注入:{}", name);
}
@PostConstruct
public void init() {
log.debug("初始化");
}
@PreDestroy
public void destroy() {
log.debug("销毁");
}
}
执行顺序:构造,依赖注入,初始化,销毁
编写自定义Bean的后处理器,需要实现InstantiationAwareBeanPostProcessor和DestructionAwareBeanPostProcessor接口,并加上@Component注解,对lifeCycleBean的生命周期过程进行扩展。
@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
@Override
// 实例化前(即调用构造方法前)执行的方法
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 实例化前执行,如@PreDestroy");
// 返回null保持原有对象不变,返回不为null,会替换掉原有对象
return null;
}
@Override
// 实例化后执行的方法
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
log.debug("<<<<<<<<<<< 实例化后执行,这里如果返回 false 会跳过依赖注入阶段");
// return false;
}
return true;
}
@Override
// 依赖注入阶段执行的方法
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");
return pvs;
}
@Override
// 销毁前执行的方法
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<<销毁之前执行");
}
@Override
// 初始化之前执行的方法
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如 @PostConstruct、@ConfigurationProperties");
return bean;
}
@Override
// 初始化之后执行的方法
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("lifeCycleBean"))
log.debug("<<<<<<<<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如 代理增强");
return bean;
}
}
模板方法
模板方法:将可扩展的位置留坑,然后定义一个接口,实现接口并加入链表中
public class TestMethodTemplatePattern {
public static void main(String[] args) {
MyBeanFactory beanFactory = new MyBeanFactory();
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Autowired"));
beanFactory.addBeanPostProcessor(bean -> System.out.println("解析 @Resource"));
beanFactory.getBean();
}
static class MyBeanFactory {
public Object getBean() {
Object bean = new Object();
System.out.println("构造:" + bean);
System.out.println("依赖注入:" + bean);
for (BeanPostProcessor processor : processors) {
processor.inject(bean);
}
System.out.println("初始化:" + bean);
return bean;
}
private List<BeanPostProcessor> processors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
processors.add(beanPostProcessor);
}
}
interface BeanPostProcessor {
void inject(Object bean);
}
}
Bean后处理器
Bean后处理器:为Bean生命周期各个阶段提供扩展
GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试。
@Slf4j
public class TestBeanPostProcessor {
@Test
public void testBeanPostProcessor() throws Exception {
// GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
// 这里用DefaultListableBeanFactory也可以完成测试,只是会比使用GenericApplicationContext麻烦一些
GenericApplicationContext context = new GenericApplicationContext();
// 用原始方法注册三个Bean
context.registerBean("bean1", Bean1.class);
context.registerBean("bean2", Bean2.class);
context.registerBean("bean3", Bean3.class);
context.registerBean("bean4", Bean4.class);
// 设置解析 @Value 注解的解析器
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
// 添加解析 @Autowired 和 @Value 注解的后处理器
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
// 添加解析 @Resource、@PostConstruct、@PreDestroy 注解的后处理器
context.registerBean(CommonAnnotationBeanPostProcessor.class);
// 添加解析 @ConfigurationProperties注解的后处理器
// ConfigurationPropertiesBindingPostProcessor后处理器不能像上面几种后处理器那样用context直接注册上去
// context.registerBean(ConfigurationPropertiesBindingPostProcessor.class);
// 需要反着来注册一下
ConfigurationPropertiesBindingPostProcessor.register(context.getDefaultListableBeanFactory());
//初始化容器,执行beanFactory后处理器,添加bean后处理器,初始化所有单例
context.refresh();
System.out.println(context.getBean(Bean4.class));
//销毁容器
context.close();
}
}
@Autowired bean后处理器执行分析
@Autowired注解解析用到的后处理器是AutowiredAnnotationBeanPostProcessor
1.扫描被@Autowired标识的属性,封装成InjectionMetadata。
2.调用inject方法按类型查找值并使用反射进行赋值
a.反射获取到标识的属性
b.将这个属性封装成DependencyDescriptor对象
c.执行beanFactory的doResolveDependency获取到这个bean的值(前提该bean已注册)
d.给标识的属性进行赋值
Bean工厂后处理器
探究一下@Component、@ComponentScan、@Bean、@MapperScan这些注解分别是由哪个后处理器来解析的。
@Slf4j
public class TestBeanFactoryPostProcessors {
@Test
public void testBeanPostProcessors() throws IOException {
// ⬇️GenericApplicationContext 是一个【干净】的容器,默认不会添加任何后处理器,方便做测试
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
// 添加Bean工厂后处理器ConfigurationClassPostProcessor
// 解析@ComponentScan、@Bean、@Import、@ImportResource注解
context.registerBean(ConfigurationClassPostProcessor.class);
// 添加Bean工厂后处理器MapperScannerConfigurer,解析@MapperScan注解
context.registerBean(MapperScannerConfigurer.class, beanDefinition -> {
// 指定扫描的包名
beanDefinition.getPropertyValues().add("basePackage", "top.jacktgq.mapper");
});
// ⬇️初始化容器
context.refresh();
for (String name : context.getBeanDefinitionNames()) {
System.out.println(name);
}
// ⬇️销毁容器
context.close();
}
}
@Component、@Bean对应的Bean工厂后处理器是ConfigurationClassPostProcessor;
@MapperScan对应的Bean工厂后处理器是MapperScannerConfigurer
组件扫描过程原理
Bean工厂后处理器来解析@Component注解
1.查找某个类下的的某个注解对象
ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
2.获取ComponentScan的包名进行转变路径
3.根据获取路径获取路径下的所有class资源
4.检查class资源是否加了@Component注解
5.注册为beanDefinition
6.将Bean定义加入工厂
Bean工厂后处理器来解析@Bean注解
1.读取有@Bean注解的类
2.获取被@Bean注解标识的方法
3.先有工厂对象(含有@Bean的类),再调用方法生产对象
4.获取beanDefinition
// 这里不需要指定类名了,因为最终的BeanDefinition是Config类中加了@Bean属性的方法的返回值的类型的定义。
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
builder.setFactoryMethodOnBean(annotatedMethod.getMethodName(), "config");
//设置自动装配方法参数
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
if (initMethod.length() > 0) {
builder.setInitMethodName(initMethod);
}
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition(annotatedMethod.getMethodName(), beanDefinition);
Bean工厂后处理器来解析@Mapper注解
1.获取被@Mapper注解标识的类资源
2.判断是否为接口类型
3.将该资源注册为beanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(classMetadata.getClassName()).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition();
4.注册
Aware和InitializingBean接口
Aware 接口用于注入一些与容器相关信息,例如:
a. BeanNameAware 注入 Bean 的名字
b. BeanFactoryAware 注入 BeanFactory 容器
c. ApplicationContextAware 注入 ApplicationContext 容器
d. EmbeddedValueResolverAware 注入 解析器,解析${}
public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
@Override
public void setBeanName(String name) {
log.debug("当前bean:" + this + ",实现 BeanNameAware 调用的方法,名字叫:" + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
log.debug("当前bean:" + this + ",实现 ApplicationContextAware 调用的方法,容器叫:" + applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
log.debug("当前bean:" + this + ",实现 InitializingBean 调用的方法,初始化");
}
@Autowired
public void aaa(ApplicationContext applicationContext) {
log.debug("当前bean:" + this +",使用 @Autowired 容器是:" + applicationContext);
}
@PostConstruct
public void init() {
log.debug("当前bean:" + this + ",使用 @PostConstruct 初始化");
}
}
定义一个MyBean类,实现BeanNameAware、ApplicationContextAware和InitializingBean接口并实现其方法,再定义两个方法,其中一个加@Autowired注解,注入ApplicationContext容器,另一个加@PostConstruct注解
b、c、d的功能用 @Autowired注解就能实现啊,为啥还要用 Aware 接口呢?
InititalizingBean 接口可以用 @PostConstruct注解实现,为啥还要用InititalizingBean呢?
简单地说:
@Autowired 和@PostConstruct注解的解析需要用到 Bean 后处理器,属于扩展功能,而 Aware 接口属于内置功能,不加任何扩展,Spring就能识别;
某些情况下,扩展功能会失效,而内置功能不会失效
@Autowired失效分析
Java 配置类包含 BeanFactoryPostProcessor 的情况
Aware 接口提供了一种【内置】 的注入手段,可以注入 BeanFactory,ApplicationContext;
InitializingBean 接口提供了一种 【内置】 的初始化手段;
内置的注入和初始化不收扩展功能的影响,总会被执行,因此 spring 框架内部的类常用它们。
Bean的初始化与销毁
初始化:执行优先级:@PostConstruct》InitializingBean》@Bean(initMethod)
@Slf4j
public class Bean1 implements InitializingBean {
@PostConstruct
public void init1() {
log.debug("初始化1,@PostConstruct");
}
@Override
public void afterPropertiesSet() throws Exception {
log.debug("初始化2,InitializingBean接口");
}
public void init3() {
log.debug("初始化3,@Bean的initMethod");
}
}
销毁:
@Slf4j
public class Bean2 implements DisposableBean {
@PreDestroy
public void destroy1() {
log.debug("销毁1,@PreDestory");
}
@Override
public void destroy() throws Exception {
log.debug("销毁2,DisposableBean接口");
}
public void destroy3() {
log.debug("销毁3,@Bean的destroyMethod");
}
}
对于init,三个初始化方法的执行顺序是
@PostConstruct -> InitializingBean接口 -> @Bean的initMethod
对于destory, 三个销毁方法的执行顺序是
@PreDestroy -> DisposableBean接口 -> @Bean的destroy
Scope类型
singleton:单例
prototype:多例
request:web请求
session:web的会话
application:web的ServletContext
Scope失效:单例注入多例,多例失效。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rw1CPkjP-1652622704291)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220515105829748.png)]
解决方法:
1.在SingletonBean的PrototypeBean1属性上加@Lazy注解
2.解决方法2:在PrototypeBean2的类上的@Scope注解多配置一个属性,如,@Scope(value = “prototype”, proxyMode = ScopedProxyMode.TARGET_CLASS)
3.解决方法3:使用ObjectFactory工厂类,在每次调用getProtypeBean3()方法中返回factory.getObject()
4.解决方法4:在SingletonBean中注入一个ApplicationContext,使用context.getBean(PrototypeBean4.class)获取对应的多例
AOP代理
aop是spring框架中非常重要的功能,其主要实现通常情况下是动态代理,但是这个说法并不全面,还有另外两种实现:
ajc编译器:是一种编译时的代码增强
agent类加载:一种类加载时的代码增强
aop之proxy增强-jdk
jdk的动态代理,只能针对接口代理
public class AopJdkProxyTest {
@Test
public void testJdkProxy() {
// jdk的动态代理,只能针对接口代理
// 目标对象
Target target = new Target();
// 用来加载在运行期间动态生成的字节码
ClassLoader loader = AopJdkProxyTest.class.getClassLoader();
Foo fooProxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (proxy, method, args) -> {
System.out.println("before...");
Object result = method.invoke(target, args);
System.out.println("after...");
return result; // 让代理也返回目标方法执行的结果
});
fooProxy.foo();
}
}
interface Foo {
void foo();
}
@Slf4j
final class Target implements Foo {
public void foo() {
log.debug("target foo");
}
}
jdk动态代理总结:
代理对象和目标对象是兄弟关系,都实现了Foo接口,代理对象类型不能强转成目标对象类型;
目标类定义的时候可以加final修饰。
aop之proxy增强-cglib
public class AopCglibProxyTest {
@Test
public void testCglibProxy1() {
// 目标对象
Target target = new Target();
Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("before...");
Object result = method.invoke(target, args); // 用方法反射调用目标
System.out.println("after...");
return result;
});
System.out.println(fooProxy.getClass());
fooProxy.foo();
}
@Test
public void testCglibProxy2() {
// 目标对象
Target target = new Target();
Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("before...");
// proxy 它可以避免反射调用
Object result = proxy.invoke(target, args); // 需要传目标类
System.out.println("after...");
return result;
});
System.out.println(fooProxy.getClass());
fooProxy.foo();
}
@Test
public void testCglibProxy3() {
// 目标对象
Foo fooProxy = (Foo) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("before...");
// proxy 它可以避免反射调用
Object result = proxy.invokeSuper(obj, args); // 不需要目标类,需要代理自己
System.out.println("after...");
return result;
});
System.out.println(fooProxy.getClass());
fooProxy.foo();
}
}
interface Foo {
void foo();
}
@Slf4j
class Target implements Foo {
public void foo() {
log.debug("target foo");
}
}
cglib动态代理总结:
代理类不需要实现接口;
代理对象和目标对象是父子关系,代理类继承于目标类;
目标类定义的时候不能加final修饰,否则代理类就无法继承目标类了,会报java.lang.IllegalArgumentException: Cannot subclass final class top.jacktgq.proxy.cglib.Target异常;
目标类方法定义的时候不能加final修饰,否则代理类继承目标类以后就不能重写目标类的方法了。
jdk代理原理:
// 增强处理器
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
// 代理接口
public interface Foo {
void foo();
int bar();
}
// 目标类
public final class Target implements Foo {
public void foo() {
System.out.println("target foo");
}
@Override
public int bar() {
System.out.println("target bar");
return 1;
}
}
//代理类
public class $Proxy0 implements Foo {
static Method foo;
static Method bar;
static {
try {
foo = Foo.class.getDeclaredMethod("foo");
bar = Foo.class.getDeclaredMethod("bar");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
private InvocationHandler h;
public $Proxy0(InvocationHandler h) {
this.h = h;
}
@Override
public void foo() {
try {
h.invoke(this, foo, new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public int bar() {
try {
return (int) h.invoke(this, bar, new Object[0]);
} catch (RuntimeException | Error e) {
throw e;
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
}
public class Main {
public static void main(String[] args) {
Foo proxy = new $Proxy0(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
// 1. 功能增强
System.out.println("before...");
// 2. 调用目标
return method.invoke(new Target(), args);
}
});
proxy.foo();
System.out.println("bar()方法返回值:" + proxy.bar());
}
}
spring直接代理生成class字节码代理对象
代理一点都不难,无非就是利用了多态、反射的知识
- 方法重写可以增强逻辑,只不过这【增强逻辑】千变万化,不能写死在代理内部
- 通过接口回调将【增强逻辑】置于代理类之外
- 配合接口方法反射(是多态调用),就可以再联动调用目标方法
- 会用 arthas 的 jad 工具反编译代理类
- 限制⛔:代理增强是借助多态来实现,因此成员变量、静态方法、final 方法均不能通过代理实现
方法反射优化
- 前 16 次反射性能较低
- 第 17 次调用会生成代理类,优化为非反射调用
- 会用 arthas 的 jad 工具反编译第 17 次调用生成的代理类
cglib 代理进阶
Target target = new Target();
Proxy proxy = new Proxy();
proxy.setCallbacks(new Callback[]{(MethodInterceptor) (p, m, a, mp) -> {
System.out.println("proxy before..." + mp.getSignature());
// ⬇️调用目标方法(三种)
// Object result = m.invoke(target, a); // ⬅️反射调用
// Object result = mp.invoke(target, a); // ⬅️非反射调用, 结合目标用
Object result = mp.invokeSuper(p, a); // ⬅️非反射调用, 结合代理用
System.out.println("proxy after..." + mp.getSignature());
return result;
}});
// ⬇️调用代理方法
proxy.save();
- 回调的接口换了一下,InvocationHandler 改成了 MethodInterceptor
- 调用目标时有所改进,见下面代码片段
- method.invoke 是反射调用,必须调用到足够次数才会进行优化
- methodProxy.invoke 是不反射调用,它会正常(间接)调用目标对象的方法(Spring 采用)
态方法、final 方法均不能通过代理实现