您的位置:首页 > 编程语言 > Java开发

基于javaConfig的springDataJpa+dubbo+springMvc搭建(二)

2015-12-31 01:15 721 查看
前文基本把dubbo框架搭出来了,本文在此框架,重点解决@org.springframework.transaction.annotation.Transactional带出的问题,以加入简单的权限管理功能进来为例.当然要完善这个框架之前,会先把权限的开关关闭.即注释org.exam.web.config.MvcConfig#addInterceptors方法.使用了spring data jpa,解决懒加载,可以离不开Transactional注解.不知算不算bug,到了现在的dubbox也没更改,总之就出了问题.先看看问题:一个服务实现类加了@Transactional,使用注解扫描就不能暴露服务(网上有解决办法,试了,没有效果).

具体出现问题例子:用户与角色是多对多的关系,查询列表时,没必要加载用户的角色,但查询某个用户时,可将用户的角色查询出来.

用户与角色的实体关系:

@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = Constants.TABLE_PREFIX + "user_role")
private Set<Role> roles = new HashSet<Role>();


查询用户分页数据:

public Page<User> findAll(String id, String username, Pageable pageable) {
return userRepository.findAll((root, query, cb) -> {
List<Predicate> criteria = new ArrayList<>();
if (StringUtils.hasLength(id)) {
criteria.add(cb.equal(root.get(User_.id), id));
}
if (StringUtils.hasLength(username)) {
criteria.add(cb.like(root.get(User_.username), "%" + username + "%"));
}
if (criteria.size() > 0) {
return cb.and(criteria.toArray(new Predicate[criteria.size()]));
} else {
return null;
}
}, pageable);
}


查询某个用户数据:

@Transactional(readOnly = true)//解决懒加载
public User findOne(String id) {
User user = userRepository.findOne(id);
user.getRoles().forEach(Role::getId);
return user;
}


使用扫描方法暴露Dubbo服务的主要逻辑在

com.alibaba.dubbo.config.spring.AnnotationBean
public class AnnotationBean extends AbstractConfig implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware {
//其它省略
//主要将带有com.alibaba.dubbo.config.annotation.Service注解的类注册成Bean
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (annotationPackage == null || annotationPackage.length() == 0) {
return;
}
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
// init scanner
Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");
Object scanner = scannerClass.getConstructor(new Class<?>[] {BeanDefinitionRegistry.class, boolean.class}).newInstance(new Object[] {(BeanDefinitionRegistry) beanFactory, true});
// add filter
Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");
Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);
Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));
addIncludeFilter.invoke(scanner, filter);
// scan packages
String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
Method scan = scannerClass.getMethod("scan", new Class<?>[]{String[].class});
scan.invoke(scanner, new Object[] {packages});
} catch (Throwable e) {
// spring 2.0
}
}
}
//主要将带有com.alibaba.dubbo.config.annotation.Service注解的类的方法暴露成服务.
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
//看以下注释
if (! isMatchPackage(bean)) {
return bean;
}
//如果经过了代理,这里也获取不到
Service service = bean.getClass().getAnnotation(Service.class);
if (service != null) {
ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
if (void.class.equals(service.interfaceClass())
&& "".equals(service.interfaceName())) {
if (bean.getClass().getInterfaces().length > 0) {
//经过了代理,这里也不对
serviceConfig.setInterface(bean.getClass().getInterfaces()[0]);
} else {
throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
}
}
if (applicationContext != null) {
serviceConfig.setApplicationContext(applicationContext);
if (service.registry() != null && service.registry().length > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
for (String registryId : service.registry()) {
if (registryId != null && registryId.length() > 0) {
registryConfigs.add((RegistryConfig)applicationContext.getBean(registryId, RegistryConfig.class));
}
}
serviceConfig.setRegistries(registryConfigs);
}
if (service.provider() != null && service.provider().length() > 0) {
serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(),ProviderConfig.class));
}
if (service.monitor() != null && service.monitor().length() > 0) {
serviceConfig.setMonitor((MonitorConfig)applicationContext.getBean(service.monitor(), MonitorConfig.class));
}
if (service.application() != null && service.application().length() > 0) {
serviceConfig.setApplication((ApplicationConfig)applicationContext.getBean(service.application(), ApplicationConfig.class));
}
if (service.module() != null && service.module().length() > 0) {
serviceConfig.setModule((ModuleConfig)applicationContext.getBean(service.module(), ModuleConfig.class));
}
if (service.provider() != null && service.provider().length() > 0) {
serviceConfig.setProvider((ProviderConfig)applicationContext.getBean(service.provider(), ProviderConfig.class));
} else {

}
if (service.protocol() != null && service.protocol().length > 0) {
List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
for (String protocolId : service.registry()) {
if (protocolId != null && protocolId.length() > 0) {
protocolConfigs.add((ProtocolConfig)applicationContext.getBean(protocolId, ProtocolConfig.class));
}
}
serviceConfig.setProtocols(protocolConfigs);
}
try {
serviceConfig.afterPropertiesSet();
} catch (RuntimeException e) {
throw (RuntimeException) e;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
serviceConfig.setRef(bean);
serviceConfigs.add(serviceConfig);
serviceConfig.export();
}
return bean;
}

private boolean isMatchPackage(Object bean) {
if (annotationPackages == null || annotationPackages.length == 0) {
return true;
}
//如果是JDK代理过的类,这里判断就会有错
String beanClassName = bean.getClass().getName();
for (String pkg : annotationPackages) {
if (beanClassName.startsWith(pkg)) {
return true;
}
}
return false;
}
}


因为使用了@Transactional注解,spring就会生成代理实例注册成Bean,所我所知,以上几个地方都不够严谨科学,对于新版本的spring已不能适应.因此将整个类修改如下:

来源:https://raw.githubusercontent.com/dangdangdotcom/dubbox/master/dubbo-config/dubbo-config-spring/src/main/java/com/alibaba/dubbo/config/spring/AnnotationBean.java

/*
* Copyright 1999-2012 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.config.spring;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
import com.alibaba.dubbo.common.utils.ReflectUtils;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
* AnnotationBean
*
* @author william.liangf
* @export
*/
public class AnnotationBean extends AbstractConfig implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware {

private static final long serialVersionUID = -7582802454287589552L;

private static final Logger logger = LoggerFactory.getLogger(Logger.class);

private String annotationPackage;

private String[] annotationPackages;

private final Set<ServiceConfig<?>> serviceConfigs = new ConcurrentHashSet<ServiceConfig<?>>();

private final ConcurrentMap<String, ReferenceBean<?>> referenceConfigs = new ConcurrentHashMap<String, ReferenceBean<?>>();

public String getPackage() {
return annotationPackage;
}

public void setPackage(String annotationPackage) {
this.annotationPackage = annotationPackage;
this.annotationPackages = (annotationPackage == null || annotationPackage.length() == 0) ? null
: Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
}

private ApplicationContext applicationContext;

public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
if (annotationPackage == null || annotationPackage.length() == 0) {
return;
}
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
// init scanner
Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");
Object scanner = scannerClass.getConstructor(new Class<?>[]{BeanDefinitionRegistry.class, boolean.class}).newInstance(new Object[]{(BeanDefinitionRegistry) beanFactory, true});
// add filter
Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");
Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);
Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));
addIncludeFilter.invoke(scanner, filter);
// scan packages
String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
Method scan = scannerClass.getMethod("scan", new Class<?>[]{String[].class});
scan.invoke(scanner, new Object[]{packages});
} catch (Throwable e) {
// spring 2.0
}
}
}

public void destroy() throws Exception {
for (ServiceConfig<?> serviceConfig : serviceConfigs) {
try {
serviceConfig.unexport();
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {
try {
referenceConfig.destroy();
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
}

public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
Class<?> clazz = bean.getClass();
if (isProxyBean(bean)) {
clazz = AopUtils.getTargetClass(bean);
}
Service service = clazz.getAnnotation(Service.class);
if (service != null) {
ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);
if (void.class.equals(service.interfaceClass())
&& "".equals(service.interfaceName())) {
if (clazz.getInterfaces().length > 0) {
serviceConfig.setInterface(clazz.getInterfaces()[0]);
} else {
throw new IllegalStateException("Failed to export remote service class " + clazz.getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");
}
}
if (applicationContext != null) {
serviceConfig.setApplicationContext(applicationContext);
if (service.registry() != null && service.registry().length > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
for (String registryId : service.registry()) {
if (registryId != null && registryId.length() > 0) {
registryConfigs.add((RegistryConfig) applicationContext.getBean(registryId, RegistryConfig.class));
}
}
serviceConfig.setRegistries(registryConfigs);
}
if (service.provider() != null && service.provider().length() > 0) {
serviceConfig.setProvider((ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));
}
if (service.monitor() != null && service.monitor().length() > 0) {
serviceConfig.setMonitor((MonitorConfig) applicationContext.getBean(service.monitor(), MonitorConfig.class));
}
if (service.application() != null && service.application().length() > 0) {
serviceConfig.setApplication((ApplicationConfig) applicationContext.getBean(service.application(), ApplicationConfig.class));
}
if (service.module() != null && service.module().length() > 0) {
serviceConfig.setModule((ModuleConfig) applicationContext.getBean(service.module(), ModuleConfig.class));
}
if (service.provider() != null && service.provider().length() > 0) {
serviceConfig.setProvider((ProviderConfig) applicationContext.getBean(service.provider(), ProviderConfig.class));
} else {

}
if (service.protocol() != null && service.protocol().length > 0) {
List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
// modified by lishen; fix dubbo's bug
for (String protocolId : service.protocol()) {
if (protocolId != null && protocolId.length() > 0) {
protocolConfigs.add((ProtocolConfig) applicationContext.getBean(protocolId, ProtocolConfig.class));
}
}
serviceConfig.setProtocols(protocolConfigs);
}
try {
serviceConfig.afterPropertiesSet();
} catch (RuntimeException e) {
throw (RuntimeException) e;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
serviceConfig.setRef(bean);
serviceConfigs.add(serviceConfig);
serviceConfig.export();
}
return bean;
}

public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (!isMatchPackage(bean)) {
return bean;
}
Class<?> clazz = bean.getClass();
if (isProxyBean(bean)) {
clazz = AopUtils.getTargetClass(bean);
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
String name = method.getName();
if (name.length() > 3 && name.startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())
&& !Modifier.isStatic(method.getModifiers())) {
try {
Reference reference = method.getAnnotation(Reference.class);
if (reference != null) {
Object value = refer(reference, method.getParameterTypes()[0]);
if (value != null) {
method.invoke(bean, new Object[]{value});
}
}
} catch (Exception e) {
// modified by lishen
throw new BeanInitializationException("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName(), e);
//                    logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
}
}
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
try {
if (!field.isAccessible()) {
field.setAccessible(true);
}
Reference reference = field.getAnnotation(Reference.class);
if (reference != null) {
Object value = refer(reference, field.getType());
if (value != null) {
field.set(bean, value);
}
}
} catch (Exception e) {
// modified by lishen
throw new BeanInitializationException("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName(), e);
//              logger.error("Failed to init remote service reference at filed " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
}
}
return bean;
}

private Object refer(Reference reference, Class<?> referenceClass) { //method.getParameterTypes()[0]
String interfaceName;
if (!"".equals(reference.interfaceName())) {
interfaceName = reference.interfaceName();
} else if (!void.class.equals(reference.interfaceClass())) {
interfaceName = reference.interfaceClass().getName();
} else if (referenceClass.isInterface()) {
interfaceName = referenceClass.getName();
} else {
throw new IllegalStateException("The @Reference undefined interfaceClass or interfaceName, and the property type " + referenceClass.getName() + " is not a interface.");
}
String key = reference.group() + "/" + interfaceName + ":" + reference.version();
ReferenceBean<?> referenceConfig = referenceConfigs.get(key);
if (referenceConfig == null) {
referenceConfig = new ReferenceBean<Object>(reference);
if (void.class.equals(reference.interfaceClass())
&& "".equals(reference.interfaceName())
&& referenceClass.isInterface()) {
referenceConfig.setInterface(referenceClass);
}
if (applicationContext != null) {
referenceConfig.setApplicationContext(applicationContext);
if (reference.registry() != null && reference.registry().length > 0) {
List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
for (String registryId : reference.registry()) {
if (registryId != null && registryId.length() > 0) {
registryConfigs.add((RegistryConfig) applicationContext.getBean(registryId, RegistryConfig.class));
}
}
referenceConfig.setRegistries(registryConfigs);
}
if (reference.consumer() != null && reference.consumer().length() > 0) {
referenceConfig.setConsumer((ConsumerConfig) applicationContext.getBean(reference.consumer(), ConsumerConfig.class));
}
if (reference.monitor() != null && reference.monitor().length() > 0) {
referenceConfig.setMonitor((MonitorConfig) applicationContext.getBean(reference.monitor(), MonitorConfig.class));
}
if (reference.application() != null && reference.application().length() > 0) {
referenceConfig.setApplication((ApplicationConfig) applicationContext.getBean(reference.application(), ApplicationConfig.class));
}
if (reference.module() != null && reference.module().length() > 0) {
referenceConfig.setModule((ModuleConfig) applicationContext.getBean(reference.module(), ModuleConfig.class));
}
if (reference.consumer() != null && reference.consumer().length() > 0) {
referenceConfig.setConsumer((ConsumerConfig) applicationContext.getBean(reference.consumer(), ConsumerConfig.class));
}
try {
referenceConfig.afterPropertiesSet();
} catch (RuntimeException e) {
throw (RuntimeException) e;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
referenceConfigs.putIfAbsent(key, referenceConfig);
referenceConfig = referenceConfigs.get(key);
}
return referenceConfig.get();
}

private boolean isMatchPackage(Object bean) {
if (annotationPackages == null || annotationPackages.length == 0) {
return true;
}
Class clazz = bean.getClass();
if (isProxyBean(bean)) {
clazz = AopUtils.getTargetClass(bean);
}
String beanClassName = clazz.getName();
for (String pkg : annotationPackages) {
if (beanClassName.startsWith(pkg)) {
return true;
}
}
return false;
}

private boolean isProxyBean(Object bean) {
return AopUtils.isAopProxy(bean);
}

}


本文源码:http://download.csdn.net/detail/xiejx618/9384819
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring dubbo javaConfig