◎筱米加步枪◎.Blog

Happy coding

Sping中自定义默认注解名生成器

在类中贴上@Repository等标签,相当于在Spring容器里定义了一个Bean类,这个Bean的名称如果不指定名称,将默认使用当前类名(不含包名)的首字母小写作为Bean的名字.

需求:

要确保这个Bean名称要唯一,显然这样定义的Bean名称太过简单,比较容易造成一样情况,如果能使用全类名作为Bean可防止这样的情况,因为不存在全类名一样的类.例如:org.kirinsoft.frame.AClass

技术实现:

指定定义一个Bean名字生成器,实现Spring提供的BeanNameGenerator,在generateBeanName方法中设计出自己需要的Bean名称.

另外在Spring配置文件中的自动注解配置要指定名字生成器类,如:

1
2
3
4
<!-- 自动注解配置 -->
<context:annotation-config />
<context:component-scan base-package="com.kirinsoft.frame"
    name-generator="com.kirinsoft.frame.pub.UniqueBeanNameGenerator" />

具体实现方法:

1
2
3
4
5
6
7
8
9
10
/**
 * 唯一Bean名称生成器.以类全名作为Bean名称.
 */
public class UniqueBeanNameGenerator implements BeanNameGenerator{
 
    @Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        return definition.getBeanClassName();
    }
}

 

Spring中事务的作用范围

下面一种情景:

在做项目中通常会进行分层架构.假设可分为Service、Biz、Dao3层.关系如下:

一个Service类调用多个Biz类,一个Biz调用多个Dao类完成业务逻辑.

基于这种情况,通常我们把事务控制到Service层.

很当然的引入Spring中配置:(其他配置略)

1
2
3
4
5
<property name="beanNames">
            <list>
                <value>*ServiceImpl</value>
            </list>
        </property>

 

那么,引入一个问题:如果同时对Service层和Biz层加入Spring的事务配置中,是哪一层起作用呢、?

换句话说,假设一个Service有两个Biz类,那么第一个Biz类操作成功,而第二个操作失败,此时第一个Biz是否有回滚呢。?

对应的Spring配置:

1
2
3
4
5
6
<property name="beanNames">
    <list>
        <value>*ServiceImpl</value>
        <value>*BizImpl</value>
    </list>
</property>

通过实验证明可得到结论:哪个包含的范围大,哪个事务起作用。

上面的假设,Service的事务起作用,第一个Biz会被回滚掉。

Spring事务属性说明

Spring事务属性配置属性说明如下:

PROPAGATION_REQUIRED

【支持当前事务,如果当前没有事务,就新建一个事务。(常用)】


PROPAGATION_SUPPORTS

【支持当前事务,如果当前没有事务,就以非事务方式执行】


PROPAGATION_MANDATORY

【支持当前事务,如果当前没有事务,就抛出异常】


PROPAGATION_REQUIRES_NEW

【新建事务,如果当前存在事务,把当前事务挂起】


PROPAGATION_NOT_SUPPORTED

【以非事务方式执行操作,如果当前存在事务,就把当前事务挂起】


PROPAGATION_NEVER   

【以非事务方式执行,如果当前存在事务,则抛出异常】


PROPAGATION_NESTED 

【如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作】


-Exception表示有Exception抛出时,事务回滚。-代表回滚+就代表提交

readonly 就是read only, 设置操作权限为只读,一般用于查询的方法,优化作用

Spring AOP 之 RegexpMethodPointcutAdvisor

昨天,做了有关日志的AOP,对相关的AOP知识总结如下:

1.引入AOP(Aspect Oroented Programming) 面向切面编程,是消除代码重复的一种方法。

2.Spring AOP 中提供了两种PointcutAdvisor,分别是:

 ①org.springframework.aop.support.RegexpMethodPointcutAdvisor  (需要加上完整类名,可以用Spring提供的匹配方式)

 ②org.springframework.aop.support.NameMatchMethodPointcutAdvisor(只需要方法名,不用加类名)

今天,主要来说明下RegexpMethodPointcutAdvisor的用法。贴一个例子来说明,一些说明都写在注释中~看贴的代码:

 感觉这么多开源东西中,最需要研究的就是Spring了~~ = =|| 继续study~~

No Hibernate Session bound to thread,and configuration does not allow creation错误解决方案

忽遇如下错误:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

百度得解:

因:将对应操作入事务即可

方法:于Spring配置文件的事务拦截器中加入对应的类即可~

出现Unable to find Bean with name XXX 可能原因

今天在公司做项目中,

由Ctrl层 >>> Biz层>>> Dao层 。在Ctrl注入Biz层类 ,在Biz层类注入Dao层类,使用注解的方式进行注入,例如,在Biz层注入Dao层的时候,首先需要将Dao层暴露出来,也就是将这个类标上 @Repository等注解,不然可能会出现Unable to find Bean with name的错误。原理实际上就是定义了一个Bean,没有定义的Bean使用注入自然是找不到这个Bean对象咯~~

换句话说若出现:Unable to find Bean with name 这种错误,不妨看看被注入类是否暴露给其他类咯~~也许是这个问题~

Spring中ApplicationContextAware接口用法

加载Spring配置文件时,如果Spring配置文件中所定义的Bean类,如果该类实现了ApplicationContextAware接口,那么在加载Spring配置文件时,会自动调用ApplicationContextAware接口中的

public void setApplicationContext(ApplicationContext context) throws BeansException

方法,并且自动可获得ApplicationContext 对象。前提必须在Spring配置文件中指定改类。

一个Demo程序如下:

 

Spring配置文件中配置:

1
<bean id="springContext" class="com.shine.spring.SpringContextHelper"></bean>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * ApplicationContext的帮助类
 * 自动装载ApplicationContext
 *
 * @author ChenST
 * @create 2010-6-24
 *
 */
public class SpringContextHelper implements ApplicationContextAware {
     
    private static ApplicationContext context ;
     
    /*
     * 注入ApplicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext context)
            throws BeansException {
        //在加载Spring时自动获得context
        SpringContextHelper.context = context;
        System.out.println(SpringContextHelper.context);
    }
     
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

Spring中抽象类不能注入属性

昨天做项目的时候,因为注入用的很爽,自然而然的在什么类下都用注入,结果出问题,注入的属性都是为null,查了一下,会不会是抽象类的问题呢,百度之,得下面的答案:

抽象类不能生成实例对象,spring无法注入 。
因为spring的原理是启动服务器时读取配置文件,取得类名后利用反射机制在spring上下文中生成一个单例的对象,由spring注入属性并维护此对象的状态,抽象类在反射生成对象时就已经失败了,后面的不会进行。

Spring2.5常用注解

公司代码很多Spring注解,下午花了点时间学习了下。贴个小案例来使用这些注解:

学习的注解列表

@Component
@Service
@Repository
@Controller
@Autowired
@Qualifier
@Resource
@PostConstruct
 @PreDestroy

1.水果接口

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 水果接口
 *
 * @author ChenST
 *
 */
public interface Fruit {
    /**
     * 获取水果的名字
     * @return
     */
    public String getName();
}

2.苹果类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 苹果
 * @author ChenST
 *
 */
@Service
public class Apple implements Fruit {
 
    /*
     * (non-Javadoc)
     * @see com.spring.annotation.Fruit#getName()
     */
    public String getName() {
        return "苹果";
    }
}

3.梨类

1
2
3
4
5
6
7
8
9
10
11
12
/**
 * 梨
 * @author ChenST
 *
 */
@Service
public class Pear implements Fruit {
 
    public String getName() {
        return "梨";
    }
}

4.人类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
 * 人,拥有水果
 * @author ChenST
 *
 */
/*
 * @Service表示定义个Bean对象默认Bean的名字为
 * 类的第一个字母小写名字,例如Human为human
 * @Service("name")也可以自己指定名字name
 * ----------以下四种注解是等效的,只是意义不同
 * @Component 比较中立的类进行注释
 * @Service   表示服务层
 * @Repository表示持久层
 * @Controller表示控制层
 */
@Service
public class Human {
     
    /** 表示拥有水果 */
    /*@Autowired(required = false)表示不确定
     *Spring容器中拥有某个类的Bean时候,这样Spring
     *找不到这个Bean时也不报错
     *
     *@Autowired注解表示自动注入对象。在配置文件中需要配置
     *<context:annotation-config />
     *<context:component-scan base-package="*"/>
     *
     *@Qualifier("apple")表示当这个fruit有两个实现类时
     *指定其中一个。负责会报错
     *
     *@Resource注释与Autowired差不多,Resource可以通过
     *name和type来指明要注入的类
     */
    //@Autowired
    //@Qualifier("apple")
    //@Resource(name="apple")
    @Resource(type=Apple.class)
    private Fruit fruit;
     
    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
 
    /**
     * 吃水果
     */
    public void eat(){
        System.out.println("我在吃"+this.fruit.getName());
    }
     
    /*
     * @PostConstruct表示Spring容器初始化后调用
     */
    @PostConstruct
    public void eatBegin(){
        System.out.println("我要开始吃了");
    }
     
    /*
     * @PreDestroy表示Spring容器销毁之前调用
     */
    @PreDestroy
    public void eatFinish(){
        System.out.println("吃完了");
    }
}

5.测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 测试类
 *
 * @author ChenST
 *
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Human human=(Human) ctx.getBean("human");
        human.eat();
    }
}

5.applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     
    <!-- 自动注解配置 -->
    <context:annotation-config />
    <context:component-scan base-package="*" />
</beans>

6.运行结果

1
2
3
我要开始吃了
我在吃苹果
吃完了

Spring中进行测试-Junit框架的扩展

利用Spring来进行测试。首先看看下面几个类。【参照网上的资料】

1.AbstractSpringContextTests 类是针对所有测试情景的类,一般不使用,而是使用他们的之类。

2.AbstractDependencyInjectionSpringContextTests 类继承了AbstractSpringContextTests是一个针对所有测试的超类,具体依赖于Spring上下文。可支持依赖注入

3.AbstractTransactionalSpringContextTests 类继承了AbstractDependencyInjectionSpringContextTests,继承该类的测试用例在spring管理的事务中进行,测试完后对数据库的记录不会造成任何影响。你对数据库进行一些操作后,它会自动把数据库回滚,这样就保证了你的测试对于环境没有任何影响。

测试用例需实现protected abstract String[] getConfigLocations()方法来获取上下文。

1.创建一个测试类的基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * Spring测试的基类
 *
 * @author ChenST
 *
 */
public abstract class BaseSpringTest extends AbstractDependencyInjectionSpringContextTests {
     
    /**
     * 获取上下文spring context,该路径是在classpath下的路径
     */
    public String[] getConfigLocations() {
        String[] configLocations = { "applicationContext.xml" };
        return configLocations;
    }
}

2.测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 测试用例,测试Dao的方法getUserInfo(String userCode)
 *
 * @author ChenST
 *
 */
public class UsersDaoTest extends BaseSpringTest {
     
    /** 用户Dao,注入实现 */
    private UsersDAO userDao;
     
    public void setUserDao(UsersDAO userDao) {
        this.userDao = userDao;
    }
 
    /**
     * 测试getUserInfo()方法,需要以test开头
     */
    public void testGetUserInfo(){
        Users user=userDao.getUserInfo("004");
        System.out.println(user.getDepartment().getDepName());
    }
}

可通过MyEclipse中的Outline透视图中进行单个方法的测试或者整个类的测试。