Spring 学习笔记(3)

l       Spring提供的RMI

假如我们在本地创建一个用户管理系统,使用User对象代表一个用户,定义一个服务接口UserService,并且有一个默认实现类UserServiceImpl。类结构图如下:

我们准备在Spring中将UserService作为一个RMI服务输出。步骤如下:

1)        xml文件中配置如下:

<!--定义UserServiceImpl -->

<bean id=”userService” class=”UserServiceImpl”>

<!--UserServiceImpl类和UserService 接口注入Spring容器-->

<bean id=”rmiService” class=”org.springframework.remoting.rmi.RmiServiceExporter”>

       <property name=”serviceName” value=”UserService”/>

       <property name=”service” ref=”userService”/>

       <property name=”serviceInterface” value=”UserService”/>

       <property name=”registryPort” value=”1099”/>

</bean>

2)        编写main启动Spring容器,main方法如下:

new ClassPathXmlApplicationContext(config.xml);

3)        客户端可以直接在xml配置文件中定义UserService并直接使用。如下:

       <bean id=”userService” class=” org.springframework.remoting.rmi.RmiProxyFactoryBean”>

              <property name=”serviceUrl” value=” rmi://localhost:1099/UserService”/>

              <property name=”serviceInterface” value=”UserService”/>

       </bean>

如果服务端不是通过Spring发布的服务,也可以通过如下代码实现:

public class Client(){

       public static void main(String [] args) throws Exception{

              RmiProxyFactoryBean fc = new RmiProxyFactoryBean();

              fc.setServiceInterface(UserService.class);

              fc.setServiceUrl(“rmi://localhost:1099/UserService”);

              fc.afterPropertiesSet();

              //获取UserService服务接口

              UserService us = (UserService)fc.getObject();

              //调用UserService

              us.creat(“creat”,”password”);.

}

}

l       Spring邮件服务

Spring提供了非常方便的Mail抽象层,它通过一个MailSender接口封装了邮件发送Bean。发送邮件的具体步骤如下:

简单邮件实例:SimpleMailMessage封装了纯文本的简单邮件。

1)        由于JavaMail的实现库并没有集成到JDK 5.0中,需要手动从SUN下载mail.jaractivation.jar这两个库。

2)        编写Springconfig.xml文件,定义mailSender Bean,把发送邮件所需要的所有配置注入到Bean中。

<bean id=”mailSender” class=”org.springframework.mail.javamail.JavaMailSenderImpl”>

       <property name=”host” value=”smtp.gmail.com”/>

<property name=”port” value=”465”/>

<property name=”username” value=”guangxu”/>

<property name=”password” value=”123”/>

<property name=”javaMailProperties” >

       <props>

              <prop key=”mail.smtp.auth”>true</prop>

              <prop key=”mail.smtp.starttls.enable”>true</prop>

              <prop key=”mail.smtp.socketFactory.class”>java.net.ssl.SSLSocketFactory

</prop>

       </props>

</property>

3)        编写程序发送邮件:

ApplicationContext ct = new ClassPathXmlApplicationContext(“config.xml”);

JavaMailSender mailSender = (JavaMailSender)ct.getBean(“mailSender”);

//创建一个纯文本邮件

SimpleMailMessage mail = new SimpleMailMessage();

mail.setFrom(“guangxu@gmail.com”);

mail.setTo(“123@gmail.com”);

mail.setSubject(“A text Mail”);

mail.setText(“测试邮件发送”);

mailSender.send(mail);

MIME邮件实例:Spring提供了一个MimeMessageHelper助手类来操作MimeMessage

只需更改邮件发送代码为:

ApplicationContext ct = new ClassPathXmlApplicationContext(“config.xml”);

JavaMailSender mailSender = (JavaMailSender)ct.getBean(“mailSender”);

//创建一个带附件的邮件

MimeMessage mime = mailSender.creatMimeMessage();

//创建Helper实例并声明编码为UTF-8true表示Multipart

MimeMessageSender helper = new MimeMessageSender(mime,true,”UTF-8”);

helper.setFrom(“guangxu@gmail.com”);

helper.setTo(“123@gmail.com”);

helper.setSubject(“A text Mail”);

helper.setText(“<html><body>访问我的书店”+”<a href=’http://www.shanshibook.com’ target=’_blank’>”+”<imag src=’cid:logo’></a></body></html>”);

//添加一个嵌入的图片:

Helper.addInline(“logo”,new ClassPathResource(“logo.gif”));

//添加一个普通的附件

Helper.addAttachment(“freebsd.gif”,new ClassPathResource(“freebsd.gif”));

//发送

mailSender.send(mime);

l       Spring任务调度服务

JDK提供了一个Timer类,可以周期性的执行某个任务,Spring把它装成ScheduledTimerTask,并且提供开源的Quaitz调度器。

假如我们要周期性的把日志内容发送给系统管理员。

使用ScheduledTimerTask的示例如下:

1)        需要定义一个任务,它派生自TimerTask

public class ReportTimerTask extends TimerTask{

       public void run(){

       String log = “read from log file”+new Date();

System.out.println(log);

try{

              Thread.sleep(10000);//模拟一个耗时的任务

}catch(InterruptedException e){

       e.printStackTrace(e);

}

                     public void sendMail(){}

}

}

2)        XML配置文件中定义reportTask,并把依赖注入scheduledTask

<bean id=”reportTask” class=”ReportTimerTask”/>

<bean id=”scheduledTask” class=”org.springframework.scheduling.timer.ScheduledTimerTask”>

      <!--启动后等待10秒,然后开始执行 -->

       <property name=”delay” value=”10000”/>

              <!--60秒执行一次-->

       <property name=”period” value=”60000”/>

<property name=”timerTask” value=” reportTask”/>

3)        reportTask定义了一个独立的任务,而scheduledTask定义了一个周期性的任务。最后,通过定义一个timerFactory来启动这个周期性任务。

<bean id=” timerFactory” class=”org.springframework.scheduling.timer.TimerFactoryBean”/>

       <property name=” scheduledTimerTasks” >

              <list>

                     <ref bean=” scheduledTask”/>

              </list>

       </property>

</bean>

4)        编写main,启动Spring容器。

public static void main(String []args){

       new ClassPathXmlApplicationContext(“config.xml”);

try{

Threed.sleep(300000);//运行这些时间后自动停止

}catch(InterruptedException e){

       System.exit();

}

}

使用Quaitz调度器的示例:

首先来介绍Quaitz实现任务调度的几个关键概念。

1)        Job:定义一个任务。

2)        Trigger:定义一个触发器,表示应该如何触发一个Job的执行。可以实现某一时刻触发或者周期性的触发。

3)        Scheduler:真正调度任务的调度器,通过scheduleJob(Job, Trigger)方法就把一个关联了TriggerJob对象放入了调度器中执行。

我们想设计一个检查磁盘剩余空间的CheckDiskFreeSpace。步骤如下:

1)        编写任务程序:

public class CheckDiskFreeSpace{

       public void check(){

              long freeSpace = Math.random()>0.5?10000000:20000000

              System.out.println(“Check disk free space at”+new Date());

              if(freeSpace<100*1024*1024){    

                     System.out.println(“Warning!”);

}

}

}

2)        config.xml文件中将其包装为JobDetailBean

<bean name=” checkDisk” class=” CheckDiskFreeSpace”/>

<bean name=”checkDiskJob” class=”org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean”>

       <property name=”targetObject” ref=” checkDisk”/>

       <property name=” targetMethod” value=”check”/>

<property name=”concurrent” value=”false”/>//设置这个checkDiskJob能不能同时执行

              </bean>

3)        定义Trigger,它定义了合适触发Job的执行。Spring封装了两种常用的TriggerBean,一种是SimpleTriggerBean可以周期性的执行Job,一种是CronTriggerBean可以在指定时间执行JobconExpression的写法可以查看相关文档。

SimpleTriggerBean配置如下:

<bean id=” repeatTrigger” class=”org.springframework.scheduling.quartz.SimpleTriggerBean”>

       <property name=”jobDetail” ref=” checkDiskJob”/>

       <!--1分钟后启动-->

       <property name=”startDelay” value=”60000”/>

       <!--5分钟检查一次-->

       <property name=”repeatInterval” value=”300000”/>

</bean>

CronTriggerBean配置如下:

<bean id=”cronTrigger” class=”org.springframework.scheduling.quartz.CronTriggerBean”>

       <property name=”jobDetail” ref=” checkDiskJob”/>

       <!--每周周一至周五中午1200执行-->

       <property name=”cronExpression” value=”0 0 12 ? * MON-FRI”/>

</bean>

4)        在配置文件中定义一个Scheduler,然后将所有的TriggerBean都注入进去。如下:

<bean id=”schedule” class=” org.springframework.scheduling.quartz.SchedulerFactoryBean”/>

       <property name=”triggers”>

              <list>

                     <ref bean=”repeatTrigger”/>

                     <ref bean=”cronTrigger”/>

       </property>

5)        编写main启动Spring容器:

Public static void main(String []args){

       New ClassPathXmlApplicationContext(“config.xml”);

}

l       Spring JMS(Java Message Service)服务:

如果不适用Spring提供的功能,则在使用JMS前首先要引入编译好的mom4j 1.1版本的jar包。为了能发送JMS消息,需要从JNDI获得ConnectionFactoryDestination对象,ConnectionFactory用于创建到JMS服务器的链接,Destination则指定了消息的目的地。接收JMS消息和发送类似,也要通过ConnectionFactory创建到JMS服务器的链接,Destination指定从何处接收消息。此外,接收者必须实现MessageListener接口以便服务器回调。最后,在main方法中启动JMS服务器,然后分别启动发送和接受线程。

直接使用JMS API相当复杂,而SpringJMS提供了非常简便的封装。通过使用Spring提供的JmsTemplate模板,操作JMS就很简单了。如下步骤:

1)        利用JmsTemplateSender只需要被注入JmsTemplate,发送的消息通过MessageCreator以回调的方式创建。

public class Sender{

       private JmsTemplate jsmTemp;

       public void setJmsTemp(JmsTemplate jsmTemp){

       this. jsmTemp= jsmTemp;

}

public void send(final String text){

       Sysytem.out.println(“Send:”+text);

       jsmTemp.send(new MessageCreator(){

public Message creatMessage(Session session) throws JMSException{

return session.creatTextMessage(text);

}

});

}

}

2)        所需的JMS资源全部定义在XML配置文件中:

<bean id=”jmsConnectionFactory” class=”org.springframework.jndi.JndiObjectFactoryBean”>

       <property name=”jndiName value=”QueueConnectionFactory”/>

</bean>

<bean id=”jmsQueue” class= “org.springframework.jndi.JndiObjectFactoryBean”>

       <property name=”jndiName” value=”jms/queue”/>

</bean>

<bean id=”jmsTemplate” class=” org.springframework.jms.core.JmsTemplate”>

       <property name=”connectionFactory” ref=” jmsConnectionFactory”/>

       <property name=”defultdestination” ref=” jmsQueue”/>

</bean>

<bean id=”sender” class=”Sender”>

       <property name=”jmsTemplate” ref=”jmsTemplate”/>

</bean>

3)        对于接受消息的Receiver类,仅实现MessageListener接口,甚至没有注入任何JMS资源。

public class Receiver implements MessageListener{

       public void onMessage(Message msg){

       if(msg instanceof TextMessage){//判断msg是否是TextMessage的实例

              TextMessage text = (TextMessage)msg;

              try{

                     System.out.println(“Receive:”+text.getText());

}catch(JMSException e){}

}

}

}

4)        Spring提供了MessageListener容器来包裹MessageListener。通常情况下,使用DefaultMessageListenerContainer就足够了,需要在XML文件中定义:

<bean id=”receiver” class=”Receiver”/>

<bean id=” listenerContainer” class=”org.springframework.jms.listener.DefaultMessageListenerContainer”>

       <property name=”connectionFactoy” ref=”jmsConnectionFactory”/>

       <property name=”destination” ref=”jmsQueue”/>

       <property name=”messageListener” ref=”receiver”/>

</bean>

5)        编写测试程序如下:

Public static void main(String []args)throws Exception{

       Mom4jUtil.startJmsServer();

       ApplicationContext ctx = new ClassPathXml ApplicationContext(“config.xml”);

       Sender sender = (Sender)ctx.getBean(“sender”);

       for(int i=0;i<10;i++){

       sender.send(“Hello“+new Date());

       Thread.sleep(1000);

}

System.exit();

}

l        SpringAcegi安全框架

Acegi为应用程序提供认证和授权的安全保护功能。在使用Acegi之前需要引入Acegi.jarcommons-codec.jar包。

1.        保护Web资源:Acegi安全框架对Web资源的保护是基于Filter的,所以我们需要多个Filter构成一个FilterChain来实现。虽然有多个Filter,但是我们只需要在web.xml中配置一个特殊的AcegiFilter,其他的Filter通过依赖注入的方式在AcegiSpring XML配置文件中定义。

1)        我们将Acegi相关的Bean全部放入security.xml中,然后在web.xml中配置ListenerFilter

web.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <!-- Acegi配置文件位置 -->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>/WEB-INF/security.xml</param-value>

</context-param>

 

    <!-- 启动Spring容器 -->

    <listener>

        <listener-class>

            org.springframework.web.context.ContextLoaderListener

        </listener-class>

    </listener>

 

    <!-- Acegi过滤器 -->

    <filter>

        <filter-name>acegiFilterChain</filter-name>

        <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>

        <init-param>

            <param-name>targetClass</param-name>

            <param-value>org.acegisecurity.util.FilterChainProxy</param-value>

        </init-param>

    </filter>

 

    <!-- Acegi过滤器URL映射 -->

    <filter-mapping>

        <filter-name>acegiFilterChain</filter-name>

        <url-pattern>*.jsp</url-pattern>

    </filter-mapping>

 

    <filter-mapping>

        <filter-name>acegiFilterChain</filter-name>

        <url-pattern>*.do</url-pattern>

    </filter-mapping>

 

    <!-- SpringDispatcherServlet -->

    <servlet>

        <servlet-name>dispatcher</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <load-on-startup>0</load-on-startup>

    </servlet>

 

    <servlet-mapping>

        <servlet-name>dispatcher</servlet-name>

        <url-pattern>*.do</url-pattern>

    </servlet-mapping>

 

</web-app>

2)        security.xml中配置好一系列的安全过滤器,以及认证管理器和决策管理器。

配置认证管理器(AuthenticationManager):该组件的任务就是对用户进行认证。认证管理器通过识别Principal(主题,通常是用户名)和Credentials(凭证,通常是口令)来确定用户的身份。Acegi提供了一个默认的AuthenticationManager的实现类ProviderManager,可以直接使用。ProviderManager并不直接去验证用户提供的PrincipalCredentials,而是将他们委托给一个或多个AuthenticationProvider来验证。ProviderManager将注意遍历每个AuthenticationProvider,只要有一个AuthenticationProvider成功的认证了用户,该认证就结束。可以使用的AuthenticationProvider如下:

a)        AuthByAdapterProvider:通过Web容器来验证。

b)        CasAuthenticationProvider:通过CAS服务器来验证用户身份。

c)        DaoAuthenticationProvider:通过数据库存储的用户名和口令信息来验证用户身份。

d)       JaasAuthenticationProvider:通过JAAS服务来验证用户身份。

e)        PasswordDaoAuthenticationProvider:通过数据库认证,但是具体过程由底层数据源完成。

f)         RememberMeAuthenticationProvider:通过浏览器端得Cookie来验证用户上次是否成功登陆并在有效期内。

g)        RemoteAuthenticationProvider:通过远程服务验证用户身份。

决策管理器(AccessDecisionManager):身份认证完毕后,还需要由决策管理器决定是否允许用户访问某一受保护的资源。该接口的核心方法如下:

public void decide(Authentication au,Object obj,ConfigAttributeDefinition con)  throws AccessDeniedException,InsufficientAuthenticationException

如果没有抛出以上异常,则认为允许访问。AccessDecisionManager的决策是基于投票方式的。让一个或多个具有投票权的AccessDecisionVoter对象进行投票,然后根据投票结果判断是否允许访问资源。

       Acegi提供了3个基本的AccessDecisionManager实现:

a)        AffirmativeBased:至少有一个投票者允许访问时,就允许访问该资源。

b)        ConsensusBased:所有投票这都允许访问时,才允许访问。

c)        UnanimousBased:如果没有投票者拒绝,就允许访问。

以上3AccessDecisionManager都有一个allowIfAllAbstainDecisions

属性,如果设置为true,就建立一个“沉默即同意”的策略,即所有投票者都弃权,也可以访问。每个AccessDecisionManager都有三种方式进行投票:ACCESS_GRANTED(赞成),ACCESS_DENIED(拒绝), ACCESS_ABSTAIN(弃权)

Acegi提供了一个投票者实现:RoleVoter。它默认只对以“ROLE_”开头的授权进行判断。

3)        配置FilterChain。详细方法不再介绍了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值