13. 实现 AOP 的方式
- 通过 ProxyFactory 实现,注意这和 Proxy 不同,如下的 User 类不需要实现接口
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(new CService());
proxyFactory.addAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before ...");
Object result = invocation.proceed();
System.out.println("After ...");
return result;
}
});
CService cService = (CService) proxyFactory.getProxy();
cService.print();
- 通过定义 ProxyFactoryBean
@Bean
public ProxyFactoryBean cServiceProxy() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(new CService());
proxyFactoryBean.addAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before ...");
Object result = invocation.proceed();
System.out.println("After ...");
return result;
}
});
return proxyFactoryBean;
}
// 调用
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CService cService = (CService) context.getBean("cServiceProxy");
cService.print();
- 通过 BeanNameAutoProxyCreator
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("CService"); //此处可为通配符, 例如: CS*
beanNameAutoProxyCreator.setInterceptorNames("myAroundAdvice"); // 拦截器的方法名
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
@Bean
public MethodInterceptor myAroundAdvice() {
return new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before ...");
Object result = invocation.proceed();
System.out.println("After ...");
return result;
}
};
}
// 调用
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CService cService = (CService) context.getBean("CService");
cService.print();
注意:CService 上面要添加 @Component 注解,1) 和 2) 则不用
- 通过 DefaultPointcutAdvisor
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("print"); // 指定要切面处理的方法
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
// 添加切面
defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before ...");
Object result = invocation.proceed();
System.out.println("Before ...");
return result;
}
});
return defaultPointcutAdvisor;
}
// DefaultAdvisorAutoProxyCreator 也可以在 AppConfig 上面通过 @Import(DefaultAdvisorAutoProxyCreator.class) 引入
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
// 调用
CService cService = (CService) context.getBean("CService");
cService.print();
注意:AppConfig 上面不要 @EnableAspectJAutoProxy 注解,否则会报错:com.sun.proxy.$Proxy19 cannot be cast to com.spring.demo.service.CService
14. Spring 中实现国际化
方式一:通过 applicationContext 获取
- 在 AppConfig 中添加如下代码
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message"); // 配置文件前缀,可传入多个
return messageSource;
}
- 在 src 目录下创建两个 properties 文件
- message.properties 存放中文信息键值对: code = 测试
- message_en.properties 存放英文信息键值对:code = test
- 调用测试
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 中文,此处其实是没有 message_en_CN.properties 配置文件,所以会取默认的 message.properties 中的值
String cnCode = context.getMessage("code", null, new Locale("en_CN"));
System.out.println(cnCode);
// 英文
String enCode = context.getMessage("code", null, new Locale("en"));
System.out.println(enCode);
方式二:自定义类实现 MessageSourceAware 接口
- 在 AppConfig 中添加如下代码
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("message"); // 配置文件前缀,可传入多个
return messageSource;
}
- 新建 MessageSourceService 实现 MessageSourceAware 接口
@Component
public class MessageSourceService implements MessageSourceAware {
@Resource
private MessageSource messageSource;
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
/**
* 定义取值的方法
*/
public String getValue(String key, String env) {
return messageSource.getMessage(key, null, new Locale(env));
}
}
// 调用
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MessageSourceService messageSourceService = (MessageSourceService) context.getBean("messageSourceService");
String cnCode = messageSourceService.getValue("code", "en_CN");
System.out.println(cnCode);
String enCode = messageSourceService.getValue("code", "en");
System.out.println(enCode);
15. 获取运行时环境
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
ConfigurableEnvironment environment = context.getEnvironment();
System.out.println(environment.getSystemProperties()); // 获取系统运行时环境信息
System.out.println(environment.getSystemEnvironment()); // 获取系统信息
System.out.println(environment.getProperty("name")); // 获取application.properties 中的键值对
16. 事件发布
主要在 Spring 初始化完成后执行;实现方式有 3 种
- 定义一个 AppListener 类并实现 ApplicationListener 接口,实现其 onApplicationEvent 方法
@Component
public class AppListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof PayloadApplicationEvent) {
PayloadApplicationEvent e = (PayloadApplicationEvent) event;
System.out.println("1. " + e.getPayload());
}
}
}
使用 ApplicationContext 直接发布
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 发布事件
context.publishEvent("aaaaaaaaaa");
- 直接注入 ApplicationEventMulticaster
@Component
public class CService {
@Resource
private ApplicationEventMulticaster applicationEventMulticaster;
public void print() {
// 在方法中执行如下代码发布
applicationEventMulticaster.multicastEvent(new PayloadApplicationEvent <String> (this, "cccc"));
System.out.println("CService print() method executed");
}
}
调用 print 方法发布
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
CService cService = (CService) context.getBean("CService");
cService.print();
- 在方法上添加 @EventListener 注解
@EventListener
public void test(ApplicationEvent event) {
if (event instanceof PayloadApplicationEvent) {
PayloadApplicationEvent < String > e = (PayloadApplicationEvent < String > ) event;
System.out.println("2. " + e.getPayload());
}
}
17. 元数据读取器
public static void main(String[] args) throws IOException {
SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader(CService.class.getName());
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取类名称
System.out.println(classMetadata.getClassName());
// 获取类注解
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
annotationMetadata.getAnnotationTypes().forEach(annotation - > System.out.println(annotation));
}
18. 获取 Spring 上下文用于获取项目初始化完成后的 Bean 对象
@Component
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(null == SpringContext.applicationContext) {
SpringContext.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name, Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
public static Environment getEnvironment() {
return applicationContext.getEnvironment();
}
}