栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring从入门到精通

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring从入门到精通

一、准备工作:

说明:本spring实例基于spring2.5.6。

1.新建实体类com.hanjun.entity.User。有以下属性及getter、setter方法:

 private String username;
 private String password;

2.新建DAO接口com.hanjun.dao.UserDao。声明方法:

public void save(User user);

3.新建DAO接口实现类com.hanjun.dao.impl.UserDaoImpl。实现方法:

 public void save(User user) {
  System.out.println("user saved!");
 }

4.新建service类com.hanjun.service.UserService。声明UserDao属性及getter、setter和add方法:

 private UserDAO userDAO;  
 public void add(User user) {
  userDAO.save(user);
 }

二、模拟spring注入

1.src下新建beans.xml,内容如下:

 
 
  
  
   
  
 

2.新建interface com.hanjun.spring.BeanFactory,声明方法:

 public Object getBean(String id);

3.新建class com.hanjun.spring.ClassPathXmlApplicationContext 实现com.hanjun.spring.BeanFactory:

 //用于存放xml中配置的bean
 private Map beans = new HashMap();
 //初使化时解析xml中配置的bean,存入beans
 public ClassPathXmlApplicationContext() throws Exception {
  SAXBuilder sb = new SAXBuilder();
  document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml")); // 构造文档对象
  Element root = doc.getRootElement(); // 获取根元素
  List list = root.getChildren("bean");// 取名字为bean的所有元素
  for (int i = 0; i < list.size(); i++) {
   Element element = (Element) list.get(i);
   String id = element.getAttributevalue("id"); //获取bean的id属性值
   String clazz = element.getAttributevalue("class");//获class属性值
   Object o = Class.forName(clazz).newInstance();
   beans.put(id, o);
   for (Element propertyElement : (List) element.getChildren("property")) {
    String name = propertyElement.getAttributevalue("name"); // userDAO
    String bean = propertyElement.getAttributevalue("bean"); // u
    Object beanObject = beans.get(bean);// UserDAOImpl instance
    String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
    Method m = o.getClass().getMethod(methodName,beanObject.getClass().getInterfaces()[0]);
    m.invoke(o, beanObject);
   }
  }
 }
 public Object getBean(String id) {
  return beans.get(id);
 }

4.测试:

 BeanFactory applicationContext = new ClassPathXmlApplicationContext();
 UserService service = (UserService)applicationContext.getBean("userService");
 User u = new User();
 u.setUsername("zhangsan");
 u.setPassword("zhangsan");
 service.add(u);


5.说明:此例有bug,因为加载bean时为顺序从上往下,所以被注入的bean需配置在上面。解析xml需要jdom.jar。

三、注入(xml)

1.引入spring.jar和commons-logging.jar

2.src下新建applicationContext.xml,内容如下:

 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
   
  
   
     
   
 


3.测试代码:

 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 UserService service = (UserService)ctx.getBean("userService");
 User u = new User();
 u.setUsername("zhangsan");
 u.setPassword("zhangsan");
 service.add(u);

4.我们常用的就是setter注入方式,spring还支持构造方法注入方式:

  
   
  

spring将id为u的bean做为参数调用UserService类对应的构造方法。如果参数不止一个,则可以通过参数类型或索引区分:

   
   

   
   

5.简单类型注入和集合类型注入,为简单类型变量注入值:

为Set类型变量注入值:

   
    
     1
     2
    

   

为List类型变量注入值:

   
    
     1
     2
     3
    

   

为Map类型变量注入值:

   
    
     
     
     
     
    

   

为Properties类型变量注入值:

   
    
     1
     2
     3
     4
    

   

四、注入(annotation)

1.applicationContext.xml中,beans标签如下,蓝色部分为新增。

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">

2.beans中增加配置如下:

 

3.在要注入的setter方法上注解@Autowired,则spring会根据参数类型找到对应类型的bean为参数,如果对应类型的bean大于1个,则会出错。解决办法为在参数类型前注解@Qualifier("bean的id或name")指定要注入哪个bean。

 @Autowired
 public void setUserDAO(@Qualifier("u") UserDAO userDAO) {
  this.userDAO = userDAO;
 }

4.相对于@Autowired,还有另一种注解方式。在要注入的setter方法上注解@Resource,spring会首先根据setter方法的名字找对应的bean做为参数,如果找不到则再根据参数的类型找对应类型的bean做为参数。@Resource(name="bean的id或name")则可以指定注入哪个bean。@Resource所用的是javax.annotation.Resource类,此类在jdk1.6引入,所以当使用jdk1.6以下版本时,想用@Resource,需引入common-annotations.jar。

5.bean的注解方式:applicationContext.xml的beans中增加配置:

然后在需要配置class类上面注解@Component,则spring初使化时会扫描指定包下的所有类,对有此注解的类自动初使化为spring的bean类,name为类名(第一个字母小写)。@Component("bean的name")则可指定bean的name。

附录,已有bean的实例如何获取bean的id

  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  IUserDao userDao = ctx.getBean(IUserDao.class);
  for(String beanId :ctx.getBeanNamesForType(IUserDao.class)){
      if(ctx.getBean(beanId)==userDao){
          System.out.println(beanId);
      }
  }

五、bean的属性

1.scope:初使化方式。默认值为singleton,即每次获取的bean为同一个。当值为prototype时,每次获取都new一个新的类。对于struts的action类,常设置为prototype。

annotation方式:class上注解@Scope("prototype")。

2.autowire:自动注入。默认值为no,即不自动注入。当值为byType时,spring会根据参数类型找对应类型的bean做为参数,如果对应类型的bean多于1个,则会出错。当值为byName时,spring会根据setter方法的名字找对应id或name的bean做为参数,例如根据setStu方法找id或name为stu的bean做为参数。

annotation方式:见spring注入(annotation)。

3.lazy-init:懒加载。默认值为false,即在spring初使化时就初使化此bean。当值为true时,则当使用到此bean时才初使化。

4.init-method="方法名":bean初使化时运行此方法。

annotation方式:在方法上注解@PostConstruct。

5.destroy-method="方法名":bean销毁时运行此方法。

annotation方式:在方法上注解@PreDestroy。

六、动态代理(jdk)

要求:在执行UserDaoImpl的所有方法前,打印"方法名 strat"。

1.新建class com.hanjun.aop.LogInterceptor。实现java.lang.reflect.InvocationHandler接口:

 private Object target;
 
 public Object getTarget() {
  return target;
 }
 public void setTarget(Object target) {
  this.target = target;
 }
 public void beforeMethod(Method m) {
  System.out.println(m.getName() + " start");
 }
 public Object invoke(Object proxy, Method m, Object[] args)
   throws Throwable {
  beforeMethod(m);
  m.invoke(target, args);
  return null;
 }

2.测试代码:

  UserDAO userDAO = new UserDAOImpl();
  LogInterceptor li = new LogInterceptor();
  li.setTarget(userDAO);
  UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), li);
  userDAOProxy.save(new User());

3.这样,就由我们写的LogInterceptor类来代理执行UserDaoImpl类的方法,可以在invok方法内任意增加代码。需要注意的是,被代理的方法必须是实现接口的方法。

七、aop(xml)

1.applicationContext.xml中,beans标签如下,蓝色部分为新增。如果被代理的方法不是实现接口的方法,还需要导入cglib-nodep-2.1_3.jar。

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

2.新建com.hanjun.aop.LogInterceptor类:

public class LogInterceptor {
 public void before() {
  System.out.println("method before");
 }
}

3.beans中增加配置:

 
 
  
   
  
 

4.测试代码:

  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService service = (UserService)ctx.getBean("userService");
  service.add(new User());

5.打印结果:

method before
user saved!

6.说明:spring的aop类需要配置为bean。aop的配置写在aop:config内。aop:aspect的ref属性指定对哪个aop类进行配置。aop:before标签的methode属性指定的方法会在pointcut织入点语句指定的对象执行前执行。

7.织入点语法:

execution(* sa* (..))  任何返回值,任何包下的以sa为命名开始的方法;

execution(* com.hanjun.dao.impl.UserDAOImpl.*(..))  指定类的任何方法;

execution(* com.hanjun.dao.impl.*.*(..))  指定包下的任何类的任何方法;

execution(* com.hanjun.dao..*.*(..))  指定包下的任何子包下的任何类的任何方法;

8.其它advice:

指定对象执行后执行指定方法

  指定对象执行出现异常时执行指定方法

9.如果多个aop的配置用同样的织入点语句,则可以在aop:config配置aop:pointcut,expression属性指定织入点语句,id为引用标识。aop:before的pointcut-ref等于aop:pointcut的id:

 
  
  
   
  
 

10.环绕拦截:在com.hanjun.aop.LogInterceptor中增加方法:

 public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
  System.out.println("method around start");
  pjp.proceed();
  System.out.println("method around end");
 }

在aop:config标签中增加配置:

11.说明:如果被代理的方法为实现接口的方法,spring会用jdk的动态代理方式。如果不是实现接口的方法,需要导入cglib-nodep-2.1_3.jar,则spring会直接操作二进制码来实现代理。

八、aop(annotation)

1.引入aspectjrt.jar和aspectjweaver.jar。

2.applicationContext.xml中,beans标签如下,蓝色部分为新增。

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

3.beans中增加配置:

4.新建com.hanjun.aop.LogInterceptor类:

@Aspect
@Component
public class LogInterceptor {
 @Before("execution(public void com.hanjun.dao.impl.UserDAOImpl.save(com.hanjun.entity.User))")
 public void before() {
  System.out.println("method before");
 }
}

5.测试代码:

  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService service = (UserService)ctx.getBean("userService");
  service.add(new User());

6.打印结果:

method before
user saved!

7.说明:在类上注解了@Aspect的类为spring的aop类;aop类本身也要spring管理,所以在类上注解@Component;在aop类的方法上注解@Before("织入点语句")则会在织入点语法指定对象运行前执行此方法。

8.织入点语法:

execution(* sa* (..))  任何返回值,任何包下的以sa为命名开始的方法;

execution(* com.hanjun.dao.impl.UserDAOImpl.*(..))  指定类的任何方法;

execution(* com.hanjun.dao.impl.*.*(..))  指定包下的任何类的任何方法;

execution(* com.hanjun.dao..*.*(..))  指定包下的任何子包下的任何类的任何方法;

9.其它advice:

@AfterReturning("织入点语句")  在织入点语句指定的对象执行完之后执行;

@AfterThrowing("织入点语句")  在织入点语句指定的对象执行出现异常时执行;

10.如果多个方法用的织入点语句相同,则可以用给一个空方法注解@Pointcut("织入点语句"),下面可以用这个方法名来共用织入点语句:

 @Pointcut("execution(* com.hanjun.dao..*.*(..))")
 public void myMethod(){}
 @AfterReturning("myMethod()")
 public void after() {
  System.out.println("method after");
 }

11.环绕拦截:

 @Around("execution(* com.bjsxt.dao..*.*(..)))")
 public void around(ProceedingJoinPoint pjp) throws Throwable{
  System.out.println("around start");
  pjp.proceed();
  System.out.println("around end");
 }

12.说明:如果被代理的方法为实现接口的方法,spring会用jdk的动态代理方式。如果不是实现接口的方法,需要导入cglib-nodep-2.1_3.jar,则spring会直接操作二进制码来实现代理。

九、datasource注入

在mysql数据库新建test数据库,新建表t_user,列userid、username、password。

1.在applicationContext.xml的beans标签中增加配置:

 
  
  
  
  
 

2.引入mysql-connector-java-5.1.13-bin.jar和spring的commons-dbcp.jar、commons-pool.jar。

3.在com.hanjun.dao.impl.UserDAOImpl类中新增DataSource属性和修改save方法:

 private DataSource dataSource;
 public DataSource getDataSource() {
  return dataSource;
 }
 @Resource
 public void setDataSource(DataSource dataSource) {
  this.dataSource = dataSource;
 }
 
 public void save(User user) {
  try {
   String sql="insert into user values(null,'zhangsan','123456')";
   Connection conn=dataSource.getConnection();
   conn.createStatement().executeUpdate(sql);
   conn.close();
  } catch (SQLException e) {
   e.printStackTrace();
  }
 }

4.这样,就可以通过spring注入的dataSource来获取Connection。

5.数据库的属性可以另外配置,src下新建jdbc.properties:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root

applicationContext.xml的beans标签中增加配置:

    >
  
   classpath:jdbc.properties
  
 

修改dataSource的配置:

    >
  
  
  
  
 

十、sessionFactory注入

1.引入hibernate的jar包。

2.在com.hanjun.entity包下新建User.hbm.xml,对User类进行hibername的实体类配置。

3.在spring的applicationContext.xml的beans标签中,增加sessionFactory的配置,将spring管理的dataSource注入进来:

    >
  
  
   
    com/hanjun/entity/User.hbm.xml
   

  
  
   
    org.hibernate.dialect.MySQLDialect
    true
   

  
 

mappingResources属性指定hibernate实体类的配置文件列表。hibernateProperties属性指定hibernate的属性配置。如果hibernate用annotation配置实体类,则sessionFactory的class改为org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean,属性mappingResources改为annotatedClasses,list的值改为类列表,如com.hanjun.entity.User。或用packagesToScan属性让spring去扫描哪些是hibernate实体类:

  
   
    com.hanjun.entity
   

  

4.修改com.hanjun.dao.impl.UserDAOImpl类:

 private SessionFactory sessionFactory;
 public SessionFactory getSessionFactory() {
  return sessionFactory;
 }
 
 @Resource
 public void setSessionFactory(SessionFactory sessionFactory) {
  this.sessionFactory = sessionFactory;
 }
 
 public void save(User user) {
  Session s = sessionFactory.openSession();
  s.beginTransaction();
  s.save(user);
  s.getTransaction().commit();
  s.close();
 }

5.测试代码:

  ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  UserService service = (UserService)ctx.getBean("userService");
  System.out.println(service.getClass());
  User u=new User();
  u.setUsername("zhangsan");
  u.setPassword("123456");
  service.add(u);

十一、管理hibernate事务

1.在applicationContext.xml中,beans标签如下,蓝色部分为新增。

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

2.在beans中增加配置:

    >
  
 

如果用annotation配置事务,还需要增加配置:

3.修改com.hanjun.dao.impl.UserDAOImpl的save方法,sessionFactory.openSession()改为sessionFactory.getCurrentSession(),不需要打开和提交事务:

 public void save(User user) {
  Session s = sessionFactory.getCurrentSession();
  s.save(user);
 }

4.在com.hanjun.service.UserService的add方法上注解@Transactional:

 @Transactional
 public void add(User user) {
   userDAO.save(user);
   Log log = new Log();
   log.setMsg("a user saved!");
   logDAO.save(log);
 }

5.说明:新增的Log类和logDAO类,在操作用户后记录日志,不详述。如此,如果在记录日志时出现异常,则新加的用户会回滚。

6.transaction的属性:

propagation : @Transactional(propagation=Propagation.REQUIRED),默认为Propagation.REQUIRED,代表如果已经有transaction,则会用这个transaction,如果没有,则会新建一个transaction。当值为Propagation.MANDATORY时,代表必须已经有transaction,如果没有会报错。当值为Propagation.REQUIRES_NEW时,代表这个方法用独立内嵌的transaction,如果回滚不会影响外面的transaction。当值为Propagation.NEVER时,代表外面必须不能有transaction,如果有则会报错。

readOnly : @Transactional(readonly=true),默认为false,如果为true,代表本事务内没有插入、修改、删除的操作,如果有则报错。此属性主要用于优化。

timeout : @Transactional(timeout=60),如果这个transaction执行超过60秒,则终止掉。

7.xml方法:

    >
  
 

 
  
   
   
  

 

 
      expression="execution(public * com.hanjun.service..*.*(..))" />
      advice-ref="txAdvice" />
 

十二、hibernateTemplate注入

1.applicationContext.xml的beans中增加配置:

 
  
 

2.修改com.hanjun.dao.impl.UserDAOImpl:

 private HibernateTemplate hibernateTemplate;
 public HibernateTemplate getHibernateTemplate() {
  return hibernateTemplate;
 }
 @Resource
 public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
  this.hibernateTemplate = hibernateTemplate;
 }
 public void save(User user) {
  hibernateTemplate.save(user);
 }

3.这样,在执行数据库操作时,直接操作就可以了,其它的不需要考虑。

4.org.springframework.orm.hibernate3.support.HibernateDaoSupport可以管理HibernateTemplate:

新建com.hanjun.dao.SuperDAO:

@Component
public class SuperDAO extends HibernateDaoSupport {
 @Resource(name="sessionFactory")
 public void setSuperSessionFactory(SessionFactory sessionFactory) {
  super.setSessionFactory(sessionFactory);
 }
}

则com.hanjun.dao.impl.UserDAOImpl不再需要hibernateTemplate属性,直接写方式即可:

@Component("userDAO") 
public class UserDAOImpl extends SuperDAO implements UserDAO {
 
 public void save(User user) {
  this.getHibernateTemplate().save(user);
 }
 
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/343594.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号