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

Spring基础、IOC(控制反转)、AOP(面向切面编程)、Log4j、注解配置

2016-12-08 10:21 716 查看

学习示例代码,包含本篇介绍的spring常用操作示例和所有所需jar文件下载地址:http://download.csdn.net/detail/daijin888888/9556697

1.什么是Spring,有什么作用

 --Spring框架属于一个解决方案框架,可以对其他技术和框架进行整合应用。

 --*好处是:将程序中的各个组件和框架技术进行解耦,便于日后系统维护,升级和扩展操作

 --在SSH中,会将Action,DAO组件都交给Spring框架管理,由Spring框架创建这些对象,建立这些对象关联。

*2.Spring都含有哪些功能

 --Spring框架提供了一个核心容器,该容器可以负责管理程序中的DAO、Action等组件(相当于工厂的作用)

 --提供了对其他技术,例如JDBC,Hibernate,Struts等框架整合API

 --提供了IOC机制,实现组件对象关系的解耦

 --提供了AOP机制,可以降低共通组件和一批目标组件的耦合度

 --提供了事务管理功能

 --提供了一个Spring MVC框架实现

*3.Spring框架容器

  Spring框架容器可以管理DAO、Action等Bean组件。该容器具有以下功能:

 --可以创建Bean组件对象

 --可以初始化Bean组件对象

 --可以销毁Bean组件对象

 --容器具有IOC和AOP机制

*4.Spring基本使用

  1)创建和管理程序组件对象

   --引入Spring IOC开发包(commons-logging.jar、spring.jar)

   --在src下添加Spring配置文件applicationContext.xml

   --将Bean组件定义到Spring配置文件applicationContext.xml中

    <bean id="标识符" class="包名.类名"></bean>

   --(编码)实例化Spring容器对象利用getBean获取Bean对象实例

      // 实例化Spring容器对象

    String conf = "/applicationContext.xml";

    ApplicationContext ac = new ClassPathXmlApplicationContext(conf);

    // 从容器中获取Bean

    类名 对象名 = (类名) ac.getBean("标识符");

示例:

[java]
view plain
copy
print?





public class JdbcCostDao implements CostDao {  
  
    public JdbcCostDao() {  
        System.out.println("JdbcCostDao构造");  
    }  
  
    public void init() {  
        System.out.println("初始化JdbcCostDao");  
    }  
  
    @Override  
    public void save() {  
        System.out.println("采用jdbc保存对象");  
    }  
  
    @Override  
    public void delete() {  
        String s = null;  
        s.length();// 模拟异常  
        System.out.println("采用jdbc删除对象");  
    }  
  
    public void destory() {  
        System.out.println("释放资源");  
    }  
}  



public class JdbcCostDao implements CostDao {

    public JdbcCostDao() {
        System.out.println("JdbcCostDao构造");
    }

    public void init() {
        System.out.println("初始化JdbcCostDao");
    }

    @Override
    public void save() {
        System.out.println("采用jdbc保存对象");
    }

    @Override
    public void delete() {
        String s = null;
        s.length();// 模拟异常
        System.out.println("采用jdbc删除对象");
    }

    public void destory() {
        System.out.println("释放资源");
    }
}


[html]
view plain
copy
print?





<bean id="jdbcCostDao" scope="singleton" init-method="init"  
     destroy-method="destory" class="com.test.dao.JdbcCostDao"></bean>  



<bean id="jdbcCostDao" scope="singleton" init-method="init"
     destroy-method="destory" class="com.test.dao.JdbcCostDao"></bean>


[java]
view plain
copy
print?





// 测试回收  
@Test  
public void test2() {  
    // 实例化Spring容器对象  
    String conf = "/applicationContext.xml";  
    AbstractApplicationContext ac = new ClassPathXmlApplicationContext(conf);  
  
    // 从容器中获取Bean  
    CostDao costDao = (CostDao) ac.getBean("jdbcCostDao");  
    costDao.save();  
  
    ac.close();// 释放容器对象-->触发释放Bean对象-->触发destory-method方法  
}  



// 测试回收
@Test
public void test2() {
// 实例化Spring容器对象
String conf = "/applicationContext.xml";
AbstractApplicationContext ac = new ClassPathXmlApplicationContext(conf);

// 从容器中获取Bean
CostDao costDao = (CostDao) ac.getBean("jdbcCostDao");
costDao.save();

ac.close();// 释放容器对象-->触发释放Bean对象-->触发destory-method方法
}
运行结果:

[plain]
view plain
copy
print?





采用jdbc保存对象  
释放资源  



采用jdbc保存对象
释放资源


   *a.控制Bean对象创建模式

       在使用时,可以在<bean>定义部分利用scope属性指定bean对象采用单例模式创建还是原型模式创建。

    scope="singleton"表示单例模式(默认值)

    scope="prototype"表示原型模式,每次调用getBean都返回一个新的Bean对象。

    如果应用Web程序中,通过配置可以扩展出request,session等属性值

   b.控制Bean对象创建时机

    scope="singleton"时,Bean对象是在容器实例化时创建。在<bean>中使用lazy-init="true"可以将Bean创建推迟到getBean方法。

     scope="prototype"时,Bean对象是在getBean方法时创建。

   c.追加初始化和销毁方法

      在<bean>中利用init-method指定一个初始化方法。可以在对象创建之后自动调用。

      <bean init-method="myinit">创建Bean对象后,会自动执行myinit方法。

    同理,可以通过destroy-method属性指定方法名。当对象被垃圾回收前自动调用该方法执行资源释放工作。该属性仅适用于singleton模式的Bean对象,当执行Spring容器close()时,容器会释放Bean单例对象,会触发destroy-method="mydestroy"中的mydesctory方法。

*5.Spring的核心IoC容器

  a.IoC概念

  Inversion of Control 控制反转或反向控制(控制转移)

  2004 Martin fowler提出的IoC思想。IOC解决两个Bean组件调用问题,可以降低两个Bean组件对象之间的耦合度。所谓控制指的是对象的创建、初始化和销毁过程。当一个组件发生变更后,该逻辑需要响应修改,控制反转确切讲应该是控制的转移,意思是将控制逻辑由使用一方转移到第三框架或容器负责。当再发生组件变更后,只需要修改框架或容器配置,不需要修改关联组件。

  IoC思想:两个组件之间调用(例如A调用B),原有方式是A负责创建B对象;现在变成了B对象由第三方框架或容器负责实例化,然后给A对象注入。即A对象获取B对象的方式发生了反转。

  IoC技术方案有两种:依赖注入(DI:Dependency Injection)和依赖查找

  Spring采用依赖注入技术实现IoC控制。

  依赖技术主要以下两种方式:

  --set方式注入(推荐)

    在A中定义setB(B b),接收传进来的B对象

  --构造方式注入

    在A中定义构造方法 public A(B b){}

  b.IoC使用方法(setter注入实现)

  --编写Action,定义到Spring配置中

  --编写DAO,定义到Spring配置中

  --在Action中定义DAO接口类型变量和setter方法

  --在Action的<bean>配置中使用下面配置

   <bean id="addCostAction"...>

     <property name="属性名"   ref="要注入的Bean对象id值">

     </property>

   </bean>

    示例:

[java]
view plain
copy
print?





public class AddCostAction {  
  
    // 属性(略)  
    // 定义注入属性  
    private CostDao costDao;  
  
    public CostDao getCostDao() {  
        return costDao;  
    }  
  
    // Spring容器会自动调用该方法注入costDao  
    public void setCostDao(CostDao costDao) {  
        this.costDao = costDao;  
    }  
  
    public String exeucte() {  
        System.out.println("开始处理资费添加请求");  
        // CostDao costDao = new JdbcCostDao();//采用注入的方式替代直接生成,以此解耦  
        costDao.save();  
        return "success";  
    }  
}  



public class AddCostAction {

// 属性(略)
// 定义注入属性
private CostDao costDao;

public CostDao getCostDao() {
return costDao;
}

// Spring容器会自动调用该方法注入costDao
public void setCostDao(CostDao costDao) {
this.costDao = costDao;
}

public String exeucte() {
System.out.println("开始处理资费添加请求");
// CostDao costDao = new JdbcCostDao();//采用注入的方式替代直接生成,以此解耦
costDao.save();
return "success";
}
}
applicationContext.xml中配置:

[java]
view plain
copy
print?





<bean id="hibernateCostDAO" class="com.test.dao.HibernateCostDAO"></bean>  
  
<bean id="addCostAction" scope="prototype" class="com.test.action.AddCostAction">  
    <!-- setter注入配置,将hibernateCostDAO对象给action的setCostDao方法传入 -->  
    <property name="costDao" ref="hibernateCostDAO"></property>  
</bean>  



<bean id="hibernateCostDAO" class="com.test.dao.HibernateCostDAO"></bean>

<bean id="addCostAction" scope="prototype" class="com.test.action.AddCostAction">
<!-- setter注入配置,将hibernateCostDAO对象给action的setCostDao方法传入 -->
<property name="costDao" ref="hibernateCostDAO"></property>
</bean>


  c.IoC使用方法(构造方式注入实现)

   --编写Action组件

   --编写DAO组件

   --在Action中添加带有DAO参数的构造方法

   --在Action的<bean>定义中,使用下面配置

    <bean id="deleteCostAction" class="">

       <constructor-arg

          index="参数索引值,从0开始" ref="要注入的Bean对象id值">

       </constructor-arg>

    </bean>

    示例:

[java]
view plain
copy
print?





public class DeleteCostAction {  
    private CostDao costDao;  
  
    public DeleteCostAction() {  
  
    }  
  
    public DeleteCostAction(CostDao costDao) {  
        this.costDao = costDao;  
    }  
  
    public String exeucte() {  
        System.out.println("删除资费请求的处理");  
        costDao.delete();  
        return "success";  
  
    }  
}  



public class DeleteCostAction {
private CostDao costDao;

public DeleteCostAction() {

}

public DeleteCostAction(CostDao costDao) {
this.costDao = costDao;
}

public String exeucte() {
System.out.println("删除资费请求的处理");
costDao.delete();
return "success";

}
}
applicationContext.xml中配置:

[html]
view plain
copy
print?





<bean id="jdbcCostDao" scope="singleton" init-method="init"  
    destroy-method="destory" class="com.test.dao.JdbcCostDao"></bean>  
  
<bean id="deleteCostAction" class="com.test.action.DeleteCostAction">  
    <!-- 构造参数注入配置,将jdbcCostDao对象给action的构造方法的第一个参数传入 -->  
    <constructor-arg index="0" ref="jdbcCostDao"></constructor-arg>  
</bean>  



<bean id="jdbcCostDao" scope="singleton" init-method="init"
destroy-method="destory" class="com.test.dao.JdbcCostDao"></bean>

<bean id="deleteCostAction" class="com.test.action.DeleteCostAction">
<!-- 构造参数注入配置,将jdbcCostDao对象给action的构造方法的第一个参数传入 -->
<constructor-arg index="0" ref="jdbcCostDao"></constructor-arg>
</bean>


   d.各种类型数据的注入

   --注入Bean对象(重点)

     <property name="属性名"  ref="Bean对象id">

     </property>

   --注入基本类型

    可以注入一个数值,一个字符串数据。

     <property name="属性名"  value="值">

     </property>

   --集合类型

    注入List,Set,Map,Properties类型

    示例:

[html]
view plain
copy
print?





<bean id="messagebean" class="com.test.action.MessageBean">  
    <property name="dir" value="D:\\images\"></property>  
    <property name="size" value="10240"></property>  
    <!-- 注入List -->  
    <property name="types">  
        <list>  
            <value>jpg</value>  
            <value>jpeg</value>  
            <value>gif</value>  
        </list>  
    </property>  
    <!-- 注入Set -->  
    <property name="cites">  
        <set>  
            <value>北京</value>  
            <value>上海</value>  
            <value>广州</value>  
        </set>  
    </property>  
    <!-- 注入Map -->  
    <property name="books">  
        <map>  
            <entry key="1001" value="Java语言基础"></entry>  
            <entry key="1002" value="JavaWeb基础"></entry>  
            <entry key="1003" value="SSH框架技术"></entry>  
        </map>  
    </property>  
    <!-- 注入Properties -->  
    <property name="dbParams">  
        <props>  
            <prop key="username">root</prop>  
            <prop key="password">123456</prop>  
            <prop key="driverClassName">com.mysql.jdbc.Driver</prop>  
        </props>  
    </property>  
</bean>  



<bean id="messagebean" class="com.test.action.MessageBean">
<property name="dir" value="D:\\images\"></property>
<property name="size" value="10240"></property>
<!-- 注入List -->
<property name="types">
<list>
<value>jpg</value>
<value>jpeg</value>
<value>gif</value>
</list>
</property>
<!-- 注入Set -->
<property name="cites">
<set>
<value>北京</value>
<value>上海</value>
<value>广州</value>
</set>
</property>
<!-- 注入Map -->
<property name="books">
<map>
<entry key="1001" value="Java语言基础"></entry>
<entry key="1002" value="JavaWeb基础"></entry>
<entry key="1003" value="SSH框架技术"></entry>
</map>
</property>
<!-- 注入Properties -->
<property name="dbParams">
<props>
<prop key="username">root</prop>
<prop key="password">123456</prop>
<prop key="driverClassName">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
对应接收注入的Java文件:

[java]
view plain
copy
print?





/** 
 * @Description:测试注入数据类别 
 * 
 */  
public class MessageBean {  
  
    private String dir;  
    private int size;  
    private List<String> types;  
    private Set<String> cites;  
    private Map<String, String> books;  
    private Properties dbParams;  
  
    public List<String> getTypes() {  
        return types;  
    }  
  
    public void setTypes(List<String> types) {  
        this.types = types;  
    }  
  
    public String getDir() {  
        return dir;  
    }  
  
    public void setDir(String dir) {  
        this.dir = dir;  
    }  
  
    public int getSize() {  
        return size;  
    }  
  
    public void setSize(int size) {  
        this.size = size;  
    }  
  
    public Set<String> getCites() {  
        return cites;  
    }  
  
    public void setCites(Set<String> cites) {  
        this.cites = cites;  
    }  
  
    public Map<String, String> getBooks() {  
        return books;  
    }  
  
    public void setBooks(Map<String, String> books) {  
        this.books = books;  
    }  
  
    public Properties getDbParams() {  
        return dbParams;  
    }  
  
    public void setDbParams(Properties dbParams) {  
        this.dbParams = dbParams;  
    }  
  
    public void show() {  
        System.out.println("--显示注入参数--");  
        System.out.println("dir:" + dir);  
        System.out.println("size:" + size);  
        System.out.println("允许上传的类型如下:");  
        for (String s : types) {  
            System.out.println(s);  
        }  
        System.out.println("城市信息:");  
        for (String s : cites) {  
            System.out.println(s);  
        }  
        System.out.println("图书信息:");  
        Set<Entry<String, String>> book = books.entrySet();  
        for (Entry en : book) {  
            System.out.println(en.getKey() + ":" + en.getValue());  
        }  
        System.out.println("显示数据库连接参数:");  
        Set keys = dbParams.keySet();  
        for (Object key : keys) {  
            System.out  
                    .println(key + "=" + dbParams.getProperty(key.toString()));  
        }  
    }  
}  



/**
* @Description:测试注入数据类别
*
*/
public class MessageBean {

private String dir;
private int size;
private List<String> types;
private Set<String> cites;
private Map<String, String> books;
private Properties dbParams;

public List<String> getTypes() {
return types;
}

public void setTypes(List<String> types) {
this.types = types;
}

public String getDir() {
return dir;
}

public void setDir(String dir) {
this.dir = dir;
}

public int getSize() {
return size;
}

public void setSize(int size) {
this.size = size;
}

public Set<String> getCites() {
return cites;
}

public void setCites(Set<String> cites) {
this.cites = cites;
}

public Map<String, String> getBooks() {
return books;
}

public void setBooks(Map<String, String> books) {
this.books = books;
}

public Properties getDbParams() {
return dbParams;
}

public void setDbParams(Properties dbParams) {
this.dbParams = dbParams;
}

public void show() {
System.out.println("--显示注入参数--");
System.out.println("dir:" + dir);
System.out.println("size:" + size);
System.out.println("允许上传的类型如下:");
for (String s : types) {
System.out.println(s);
}
System.out.println("城市信息:");
for (String s : cites) {
System.out.println(s);
}
System.out.println("图书信息:");
Set<Entry<String, String>> book = books.entrySet();
for (Entry en : book) {
System.out.println(en.getKey() + ":" + en.getValue());
}
System.out.println("显示数据库连接参数:");
Set keys = dbParams.keySet();
for (Object key : keys) {
System.out
.println(key + "=" + dbParams.getProperty(key.toString()));
}
}
}

测试程序:

[java]
view plain
copy
print?





public class TestMessageBean {  
  
    @Test  
    public void test1() {  
        String conf = "/applicationContext.xml";  
        ApplicationContext ac = new ClassPathXmlApplicationContext(conf);  
  
        MessageBean bean = (MessageBean) ac.getBean("messagebean");  
        bean.show();  
    }  
}  



public class TestMessageBean {

@Test
public void test1() {
String conf = "/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(conf);

MessageBean bean = (MessageBean) ac.getBean("messagebean");
bean.show();
}
}
测试结果:

[plain]
view plain
copy
print?





--显示注入参数--  
dir:D:\\images\  
size:10240  
允许上传的类型如下:  
jpg  
jpeg  
gif  
城市信息:  
北京  
上海  
广州  
图书信息:  
1001:Java语言基础  
1002:JavaWeb基础  
1003:SSH框架技术  
显示数据库连接参数:  
password=123456  
driverClassName=com.mysql.jdbc.Driver  
username=root  



--显示注入参数--
dir:D:\\images\
size:10240
允许上传的类型如下:
jpg
jpeg
gif
城市信息:
北京
上海
广州
图书信息:
1001:Java语言基础
1002:JavaWeb基础
1003:SSH框架技术
显示数据库连接参数:
password=123456
driverClassName=com.mysql.jdbc.Driver
username=root


6.Spring的AOP机制

 1)什么是AOP,解决什么问题

  --Aspect Oriented Programming被称为面向方面(切面)编程。

  --AOP主要解决共通组件与某一批目标组件作用关系,以低耦合方式建立关联。

  --AOP编程核心是对方面处理(共通功能)进行解耦。OOP编程核心是对象。

  --AOP编程是以OOP为基础,在OOP基础之上改善程序中对象结构,使得对象关系更加灵活,易于维护和扩展。

 

 2)AOP相关概念

  a.方面(Aspect):

    方面封装了共通处理,在AOP编程中,可以灵活作用到另外一批目标组件的方法上。

  b.切入点(Pointcut)

   切入点负责指定哪些组件和方法,是方面切入的目标。采用一个表达式指定

  c.通知(Advice)

   通知负责指定切入点和目标组件方法之间的作用时机。例如先执行目标方法,再执行方面处理。或者先执行方面处理,再执行目标方法。

   Spring提供以下5种通知类型:

  --前置通知(aop:before):先执行方面处理,再执行目标方法

  --后置通知(aop:after-returning):先执行目标方法,未抛出异常,再执行方面处理;有异常则不会执行方面组件

  --最终通知(aop:after):先执行目标方法,有无异常,都会再执行方面处理

  --环绕通知(aop:around):先执行方面处理前置部分,接着执行目标方法,然后再回到方面处理的后置部分。

  --异常通知(aop:after-throwing):先执行目标方法,发生异常再执行方面处理;没有抛出异常不会执行。

 try{

  //前置通知--执行方面处理

  //环绕的前置部分

  执行目标方法

  //环绕的后置部分

  //后置通知--执行方面处理

 }catch(){

   //异常通知--执行方面处理

  }finally{

   //最终通知--执行方面处理

  }

  d.目标组件(Target)

    切入点表达式指定的组件就是目标组件。

  e.连接点(JoinPoint)

    连接点的集合是切入点。连接点指的是方面组件与某个目标组件相结合的信息。通过该对象可以获取目标组件类型和方法等信息。

  f.动态代理(AutoProxy)

   Spring框架采用动态代理技术实现了AOP机制。

  当采用了AOP之后,Spring容器返回的目标Bean对象,是Spring动态生成的一个代理类型。该代理类负责去调用原目标组件方法和方面处理的功能。

  Spring中提供两种生成动态代理类的方法。

  --JDK Proxy API技术

    针对有接口实现的目标组件。采用实现原目标接口的方法生成一个类型。

   public class $Proxy4 implements CostDao{

     public void save(){

       //调用JdbcCostDao的save()

       //调用方面LoggerAop的功能

     }

     public void findAll(){

       //调用JdbcCostDao的findAll()

       //调用方面LoggerAop的功能

     }

  }

  --CGLIB技术

    针对没有接口实现的目标组件。采用继承方法生成一个子类。

  public class $$EnhancerByCGLIB$232 extends 原目标组件类型{

     public void save(){

       super.save();//调用原目标方法

       //调用方面组件处理

     }

  }

 3)AOP使用步骤

  a.记录用户进入系统后执行的操作

  --编写方面,将共通功能封装

  --添加Spring配置,将组件定义成方面组件

  --添加Spring配置,定义切入点

  --添加Spring配置,定义通知
方面代码:

[java]
view plain
copy
print?





public class OptLogger {  
    /** 
     * @param pjp 
     *            连接点(需用环绕通知切入) 
     * @throws Throwable 
     */  
    public Object log(ProceedingJoinPoint pjp) throws Throwable {  
        Object obj = pjp.proceed();// 执行目标组件方法处理  
        // 获取当前请求要执行的Action目标组件类型  
        String className = pjp.getTarget().getClass().getName();  
        // 获取当前请求要执行的方法名  
        String methodName = pjp.getSignature().getName();  
        // 根据类名和方法名形成key  
        String key = className + "." + methodName;  
        // 解析opt.properties,根据key获取操作动作描述  
        String optName = PropertiesUtil.getProperty(key);  
  
        System.out.println("XXX在" + new Date() + "时间做了" + optName + "操作");  
        return obj;// 将proceed目标方法结果返回  
    }  
}  
PropertiesUtil用于读取配置文件,可将特定操作(类+方法转换成中文描述)  
<pre name="code" class="java">public class PropertiesUtil {  
    private static Properties props = new Properties();  
    static{  
        try{  
            InputStream inStream = PropertiesUtil.class  
                .getClassLoader().getResourceAsStream(  
                        "opt.properties");  
            props.load(inStream);  
        }catch(Exception ex){  
            ex.printStackTrace();  
        }  
    }  
      
    public static String getProperty(String key){  
        String val = props.getProperty(key);  
        return val;  
    }  
      
}  



public class OptLogger {
/**
* @param pjp
*            连接点(需用环绕通知切入)
* @throws Throwable
*/
public Object log(ProceedingJoinPoint pjp) throws Throwable {
Object obj = pjp.proceed();// 执行目标组件方法处理
// 获取当前请求要执行的Action目标组件类型
String className = pjp.getTarget().getClass().getName();
// 获取当前请求要执行的方法名
String methodName = pjp.getSignature().getName();
// 根据类名和方法名形成key
String key = className + "." + methodName;
// 解析opt.properties,根据key获取操作动作描述
String optName = PropertiesUtil.getProperty(key);

System.out.println("XXX在" + new Date() + "时间做了" + optName + "操作");
return obj;// 将proceed目标方法结果返回
}
}
PropertiesUtil用于读取配置文件,可将特定操作(类+方法转换成中文描述)
<pre name="code" class="java">public class PropertiesUtil {
private static Properties props = new Properties();
static{
try{
InputStream inStream = PropertiesUtil.class
.getClassLoader().getResourceAsStream(
"opt.properties");
props.load(inStream);
}catch(Exception ex){
ex.printStackTrace();
}
}

public static String getProperty(String key){
String val = props.getProperty(key);
return val;
}

}
opt.properties:(使用native2ascii tool工具将中文转码)

#use jdk/bin/native2ascii tool

#以下分别对应:资费添加操作、资费删除操作

com.test.action.AddCostAction.exeucte=\u8d44\u8d39\u6dfb\u52a0\u64cd\u4f5c

com.test.action.DeleteCostAction.exeucte=\u8d44\u8d39\u5220\u9664\u64cd\u4f5c


配置代码:

[html]
view plain
copy
print?





<!-- AOP配置 -->  
<bean id="optLogger" class="com.test.aspect.OptLogger">  
<aop:config>  
    <!-- 指定切入点 -->  
    <aop:pointcut id="actionPointcut" expression="within(com.test.action.*)" />  
    <!-- 将id=optLogger的Bean指定为方面组件 -->  
    <aop:aspect id="optLoggerAspect" ref="optLogger">  
        <!-- 指定通知,控制方面和目标组件作用时机 -->  
        <aop:around pointcut-ref="actionPointcut" method="log" />  
    </aop:aspect>  
</aop:config>  



<!-- AOP配置 -->
<bean id="optLogger" class="com.test.aspect.OptLogger">
<aop:config>
<!-- 指定切入点 -->
<aop:pointcut id="actionPointcut" expression="within(com.test.action.*)" />
<!-- 将id=optLogger的Bean指定为方面组件 -->
<aop:aspect id="optLoggerAspect" ref="optLogger">
<!-- 指定通知,控制方面和目标组件作用时机 -->
<aop:around pointcut-ref="actionPointcut" method="log" />
</aop:aspect>
</aop:config>


 4)切入点表达式

  切入点是用一个表达式表示,用于指定目标及其方法。

 *a.方法限定表达式

  可以指定哪些方法启用方面组件功能

 execution(修饰符? 返回类型 方法名(参数列表) throws异常?)

 示例1:

  //匹配容器中所有Bean对象的findAll方法

  execution(* findAll(..))

  //匹配容器中所有Bean对象的find开头方法

  execution(* find*(..))

 示例2:

  //匹配JdbcCostDao所有方法

  execution(* org.dao.JdbcCostDao.*(..))

 示例3:

  //匹配org.dao包下所有类的所有方法

  execution(* org.dao.*.*(..))

  //匹配org.dao包及其子包所有类所有方法

  execution(* org.dao..*.*(..))

 *b.类型限定表达式

 可以限定某个类型的所有方法启用方面within(类型)

 示例1:

  //匹配JdbcCostDao所有方法

  within(org.dao.JdbcCostDao)

 示例2:

  //匹配org.dao下所有类的所有方法

  within(org.dao.*)

 示例3:

  //匹配org.dao下及其子包所有类所有方法

  within(org.dao..*)

 *c.Bean名称限定表达式

 可以利用Bean对象的id进行限定

 bean(id或name值)

 <bean id="" name="">

 name属性作用与id相同,id要求更严格,不允许使用/等特殊字符,name允许。

 示例1:

  //匹配容器中所有id以Dao结尾的Bean对象

  bean(*Dao)

  d.参数限定表达式

  args(参数类型)

 示例1:

  //匹配所有Bean对象中有一个参数,而且是String类型的方法

   args(java.lang.String)

 提示:上述表达式可以利用&&,||连接在一起使用。

 5)通知方法定义

  //前置通知方法

  public void xxx(){}

  //后置通知方法

  public void xxx(Object retVal){}

  参数retVal可以接收目标方法返回值

  //最终通知方法

  public void xxx(){}

  *//环绕通知方法

  public Object xxx(ProceedingJoinPoint pjp){}

  *//异常通知方法

  public void xxx(Exception e){}

  参数e可以接收目标方法抛出的异常对象

(示例:如6中用Log4j记录程序异常信息并保存下来)

7.Log4j

  log4j.jar工具是Apache组织下的一个日志组件,可以将消息按不同级别不同输出方式记录下来。

  log4j工具主要有以下3部分构成。

  --日志器Logger

    负责提供输出不同级别消息的方法。消息可以分为调试、普通、警告、错误、致命级别,不同级别信息利用不同日志器的方法输出。

  --输出器Appender

    负责控制信息输出的方式,例如控制台输出、文件输出等。

  --布局器Layout

    负责将消息格式化。

    对应关系:一个Logger可以指定多个不同的Appender,每个Appender可以指定一个Layout。

  使用步骤:

  --引入log4j.jar开发包

  --在Java代码中获取Logger对象,之后利用它的debug(),error()输出信息

  --在src下添加log4j.properties配置文件指定消息输出的级别,输出的appender和输出的layout格式。

 提示:项目中由于SSH框架利用Log4j工具输出调试和异常信息,因此遇到错误提示不明确时,可以添加log4j.properties配置将级别调到DEBUG查看。

如配置文件,log4j.properties:

[plain]
view plain
copy
print?





log4j.rootLogger=error,myconsole,myfile  
  
log4j.appender.myfile=org.apache.log4j.FileAppender  
log4j.appender.myfile.File=D:\\log4j.html  
log4j.appender.myfile.layout=org.apache.log4j.HTMLLayout  
  
log4j.appender.myconsole=org.apache.log4j.ConsoleAppender  
log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout  



log4j.rootLogger=error,myconsole,myfile

log4j.appender.myfile=org.apache.log4j.FileAppender
log4j.appender.myfile.File=D:\\log4j.html
log4j.appender.myfile.layout=org.apache.log4j.HTMLLayout

log4j.appender.myconsole=org.apache.log4j.ConsoleAppender
log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout


[java]
view plain
copy
print?





/** 
 * @Description:异常记录方面组件 
 */  
public class ExceptionLogger {  
    // 获取日志器  
    private static Logger logger = Logger.getLogger(ExceptionLogger.class);  
  
    // ex就是目标方法抛出的异常对象  
    public void logException(Exception ex) {  
        // System.out.println("将异常写入文件" + ex);  
        // 采用Log4j日志工具记录异常信息  
        logger.error(ex);  
        logger.error(ex.getStackTrace()[0]);  
    }  
}  



/**
* @Description:异常记录方面组件
*/
public class ExceptionLogger {
// 获取日志器
private static Logger logger = Logger.getLogger(ExceptionLogger.class);

// ex就是目标方法抛出的异常对象
public void logException(Exception ex) {
// System.out.println("将异常写入文件" + ex);
// 采用Log4j日志工具记录异常信息
logger.error(ex);
logger.error(ex.getStackTrace()[0]);
}
}


[html]
view plain
copy
print?





<!-- AOP配置 -->  
<bean id="exceptionLogger" class="com.test.aspect.ExceptionLogger">  
</bean>  
<!-- 指定切入点 -->  
<aop:pointcut id="daoPointcut" expression="within(com.test.dao..*)" />  
<aop:config>  
    <!-- 将id=exceptionLogger的Bean指定为方面组件 -->  
    <!-- trowing指定logException方法的参数名,用于接收目标方法抛出的异常对象 -->  
    <aop:aspect id="exceptionLoggerAspect" ref="exceptionLogger">  
        <aop:after-throwing pointcut-ref="daoPointcut"  
            method="logException" throwing="ex" />  
    </aop:aspect>  
</aop:config>  



<!-- AOP配置 -->
<bean id="exceptionLogger" class="com.test.aspect.ExceptionLogger">
</bean>
<!-- 指定切入点 -->
<aop:pointcut id="daoPointcut" expression="within(com.test.dao..*)" />
<aop:config>
<!-- 将id=exceptionLogger的Bean指定为方面组件 -->
<!-- trowing指定logException方法的参数名,用于接收目标方法抛出的异常对象 -->
<aop:aspect id="exceptionLoggerAspect" ref="exceptionLogger">
<aop:after-throwing pointcut-ref="daoPointcut"
method="logException" throwing="ex" />
</aop:aspect>
</aop:config>
在配置文件指定的地方生产文件如下:

[plain]
view plain
copy
print?





D:\\log4j.html  



D:\\log4j.html
Log session start time Wed Jun 22 17:00:13 CST 2016

Log session start time Wed Jun 22 17:03:39 CST 2016

TimeThreadLevelCategoryMessage
0mainERRORcom.test.aspect.ExceptionLoggerjava.lang.NullPointerException
1mainERRORcom.test.aspect.ExceptionLoggercom.test.dao.JdbcCostDao.delete(JdbcCostDao.java:22)
TimeThreadLevelCategoryMessage
0mainERRORcom.test.aspect.ExceptionLoggerjava.lang.NullPointerException
3mainERRORcom.test.aspect.ExceptionLoggercom.test.dao.JdbcCostDao.delete(JdbcCostDao.java:22)

8.Spring注解配置

 1)什么是注解

   注解技术是JDK5.0开始提供的。

   它的标记格式为"@名称",它可以定义在类前、方法前、成员变量前。

 2)使用注解的好处

  现在的框架都提供了注解配置,利用注解技术去简化或替代原有的XML配置。

 3)Spring的组件扫描技术

  Spring可以自动扫描指定包下的Class组件,如果发现类定义前面有以下几个标记

  @Controller(Action组件应用)

  @Service(Service业务组件应用)

  @Repository(DAO组件应用)

  @Component(其他组件应用)

  就会将该组件扫描到Spring容器,由容器负责管理和对象的创建,等价于XML中<bean>定义。

  使用方法:

   --在applicationContext.xml中开启组件扫描功能 <context:component-scan base-package="指定包路径"/>

   --在Action或DAO等组件类定义前使用上述标记。默认用类名首字母小写当id,也可以采用@Repository("指定id")格式

  其他<bean>属性注解标记:

  @Scope("prototype"或"singleton")等价于scope属性

  @PreDestory等价于destory-method属性

  @PostConstruct等价于init-method属性

  4)注入的注解

    @Resource

    @Autowired

   上面两种标记都可以实现类型匹配注入,但是如果遇到多个匹配对象时,会发生异常。这时需要指定注入哪个id的Bean

    @Resource(name="指定id")

    @Autowired()

    @Qualifier("指定id")

   上面标记可以写在变量定义前或set方法前。写在变量定义前时,set可省略。

  5)AOP注解配置

   使用方法:

   --在applicationContext.xml中开启AOP的注解配置<aop:aspectj-autoproxy/>

   --在方面组件中类定义前使用下面标记

    @Component //将Bean扫描到容器

    @Aspect //将Bean升级为方面组件

   --在方面组件中定义一个空方法,利用@Point标记定义切入表达式

    @Pointcut("切入表达式")

    public void mypoint(){}

   --在方面组件处理方法上,使用下面通知标记

    @Before 前置通知标记

    @Around 环绕通知标记

    @AfterReturning 后置通知标记

    @AfterThrowing 异常通知标记

    @After 最终通知标记

源页:

本文转自-http://blog.csdn.net/daijin888888/article/details/51735291?locationNum=10&fps=1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring AOP ioc log4j jar
相关文章推荐