Day67 Spring AOP(面向切面程式設計) 和代理設計模式

神一樣的我發表於2018-05-10

Spring AOP 概念

Spring AOP學習:
    問題:
        Spring IOC實現了物件之間依賴關係的解耦。如果開發過程中,需要更改物件,只需要
        在配置檔案中更改物件的配置路徑即可完成物件的更換。但是,在保留原有物件的基礎上
        對原有功能程式碼進行功能擴充套件,是Spring IOC所不能實現的。
    解決:
        使用Spring AOP
        特點:
            在不改變原有物件的功能程式碼的基礎上完成功能擴充套件。
    概念:
        面向切面的程式設計(擴充套件)。
    術語:
        前置通知:在原有功能執行之前擴充的程式碼。
        後置通知:在原有功能執行之後擴充的程式碼。
        切點:原有功能方法
        織入:前置通知+切點+後置通知形成切面的過程
        切面:前置通知+切點+後置通知形成的橫向執行流程。
    使用:
        Schema-based方式
        Aspectj方式
        基於Aspectj的註解方式
    流程:
        匯入jar包
        配置配置檔案
        完成擴充套件


Schema-based方式

Schema-Based方式:
    第一步:
        匯入jar包(Spring IOC包+AOP相關包)
    第二步:
        在src下建立applicationcontext.xml配置檔案
            載入Schema:
                <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
         http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
                    ">
            配置相關bean
            配置通知bean
            配置切面
    第三步:
        建立通知類
            前置通知:
                建立一個實現了MethodBeforeAdvice介面的java類
                實現介面方法before
                    引數:
                        Method arg0:切點方法物件
                        Object[] arg1:切點接收的實引數組
                        Object arg2:切點所在的物件
                在配置檔案中配置通知bean
                在切面配置中配置關聯
            後置通知
                建立一個實現了AfterReturningAdvice介面的java類
                實現介面方法afterReturning
                    引數:
                        Object arg0:切點的返回值
                        Method arg0:切點方法物件
                        Object[] arg1:切點接收的實引數組
                        Object arg2:切點所在的物件
                在配置檔案中配置通知bean
                在切面配置中配置關聯
            環繞通知
                建立一個實現了MethodInterceptor介面的java類
                實現介面方法invoke
                        引數:
                        MethodInvocation arg0:放行切點
                在配置檔案中配置通知bean
                在切面配置中配置關聯
                注意:
                    在實現方法中需要對切點方法進行放行:  Object obj=arg0.proceed();//放行,執行切點方法。
            異常通知
                建立一個實現了ThrowsAdvice介面的java類
                實現介面方法afterThrowing
                    public void afterThrowing(Exception ex) throws Throwable {
                        System.out.println("我是異常通知");
                     }
                    Exception ex:接收的是切點的異常物件。
                在配置檔案中配置通知bean
                在切面配置中配置關聯
                注意:
                    切點中的內部如果使用異常處理機制,則無法觸發異常通通知。
        萬用字元的作用:
            1   <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.demo(..))" id="my"/><!--配置切點 -->
                其中切點方式使用..表示引數個數個型別為任意,只要是方法名為demo的都會新增通知。
            2   <aop:pointcut expression="execution(* com.bjsxt.pojo.Car2.*(..))" id="my"/><!--配置切點 -->
                  *是萬用字元,表示任意的方法名,類名,包名等。

    第四步:        
        由Spring容器物件獲取切點所在bean物件
        呼叫切點方法完成功能操作。
-------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:myns="http://www.mycompany.com/schema/myns"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd
         http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        ">
    <!-- 配置bean 沒有使用Spring AOP -->
        <bean id="car" class="com.bjsxt.pojo.Car"></bean>
    <!--配置bean  使用Spring AOP-->
        <!--Schema-Based方式  -->
            <!--配置切點bean  -->
                <bean id="car2" class="com.bjsxt.pojo.Car2"></bean>
            <!--配置前置通知bean  -->
                <bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
            <!--配置後置通知bean  -->
                <bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
            <!--配置環繞通知bean  -->
                <bean id="round" class="com.bjsxt.advice.MyRound"></bean>
            <!--配置異常通知bean  -->
                <bean id="throw" class="com.bjsxt.advice.MyThrow"></bean>
            <!--配置切面  -->
            <aop:config>
                <aop:pointcut expression="execution(* com.*.pojo.Car2.*(..))" id="my"/><!--配置切點 -->
                <aop:advisor advice-ref="before" pointcut-ref="my"/><!--配置前置通知 -->
                <aop:advisor advice-ref="after" pointcut-ref="my"/><!--配置後置通知  -->
                <aop:advisor advice-ref="round" pointcut-ref="my"/><!-- 配置環繞通知 -->
                <aop:advisor advice-ref="throw" pointcut-ref="my"/><!-- 配置異常通知 -->
            </aop:config>

</beans>

基於AspectJ方式

AspectJ方式:
    第一步:
        匯入jar包(Spring IOC+AOP包)
    第二步:
        在Src下建立applicationcontext.xml
            載入Schema(IOC和AOP相關)
            配置相關bean
    第三步:
        建立通知類
            建立一個普通java類,建立四個方法。
            前置通知方法
            後置通知方法
            環繞通知方法
                public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("AspectJ方式--環繞--前置");
        Object obj=p.proceed();
        System.out.println("AspectJ方式--環繞--後置");
        return obj;
                }
            異常通知方法
        在applicationcontext.xml中配置通知bean
            <bean id="advice" class="com.bjsxt.adviceAs.Myadvice"></bean>
        在applicationcontext.xml中配置切面
            <aop:config>
                    <aop:aspect ref="advice">
                        <aop:pointcut expression="execution(* com.bjsxt.pojo.Car3.demo())" id="my1"/><!--配置切點  -->
                        <aop:before method="before" pointcut-ref="my1"/><!--前置通知  -->
                        <aop:after-returning method="after" pointcut-ref="my1"/><!--後置通知  -->
                        <aop:around method="round" pointcut-ref="my1"/><!-- 環繞通知 -->
                        <aop:after-throwing method="myThrow" pointcut-ref="my1" throwing="e"/><!--異常通知  -->
                    </aop:aspect>
            </aop:config>

第四步:
        建立Spring容器物件
        獲取切點bean物件
        呼叫切點方法
總結:
    AspectJ配置方式的通知方法中要獲取切點的引數,配置特別麻煩,切點不能通配。
    如果不需要切點的引數則使用AspectJ方式
    如果需要引數使用Schema-based方式
-------------------------------------------------------------------------

使用註解(基於AspectJ)

@Component  預設使用無參構造器
Spring預設使用JDK代理模式

基於Aspectj的註解配置AOP:
    1 匯入jar包
    2 建立Spring配置檔案並完成基礎配置
        載入Schema
        配置資料來源
        配置工廠
        配置掃描
    3 Spring使用註解配置
            在spring配置檔案中增加context的先關Schema
                <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
            在Spring配置檔案中配置註解掃描:
                 <context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
            注意:必須在Spring配置檔案中宣告使用了註解的類的包路徑
    4 使用註解替換XML的配置
        替換bean配置(通用)
            @Component
                 在類名上直接使用此註解,表示bean建立,相當於在Spring中配置了該類的bean標籤。
                類名首字母小寫即為bean 的ID
        替換切面配置
            替換切點宣告
                在切點方法上直接使用@Pointcut註解宣告切點,示例如下:
                @Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
    public void demo(){
        System.out.println("Demo.demo()");
    }
            替換通知方法的配置
                在通知類的類名上還要使用@Aspect進行宣告該類為通知類。
                在類的通知方法上使用註解
                    前置通知:@Before("切點的全限定路徑")  示例:
                            @Before("com.bjsxt.pojo.Demo.demo()")
    public void myBefore(){
        System.out.println("註解----前置通知");
    }
                    後置通知
                        @After("com.bjsxt.pojo.Demo.demo()")
    public void after(){

        System.out.println("註解---後置通知");
    }
                    環繞通知
         @Around("com.bjsxt.pojo.Demo.demo()")
    public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("註解--環繞--前置");
        Object obj=p.proceed();
        System.out.println("註解--環繞--後置");
        return obj;
    }
                    異常通知    
@AfterThrowing("com.bjsxt.pojo.Demo.demo()")
    public void myThrow(){

        System.out.println("註解---異常");
    }

注意:
    一定要將動態代理模式設定為cglib代理模式
         <!--配置動態代理模式  -->
         <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
--------------------------------------------------------------------------------------------------------------------------------------------
Spring配置檔案中的配置
        <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
        <!--配置註解掃描  -->
        <context:component-scan base-package="com.bjsxt.advice,com.bjsxt.pojo"></context:component-scan>
        <!--配置動態代理模式  -->
        <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>
切點Bean的配置:
        package com.bjsxt.pojo;

import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
public class Demo {
    @Pointcut("execution(* com.bjsxt.pojo.Demo.demo())")
    public void demo(){
        System.out.println("Demo.demo()");
    }
}
通知Bean的配置和切面的配置
package com.bjsxt.advice;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    @Before("com.bjsxt.pojo.Demo.demo()")
    public void myBefore(){
        System.out.println("註解----前置通知");
    }

    @After("com.bjsxt.pojo.Demo.demo()")
    public void after(){

        System.out.println("註解---後置通知");
    }
    @Around("com.bjsxt.pojo.Demo.demo()")
    public Object round(ProceedingJoinPoint p) throws Throwable{
        System.out.println("註解--環繞--前置");
        Object obj=p.proceed();
        System.out.println("註解--環繞--後置");
        return obj;
    }
    @AfterThrowing("com.bjsxt.pojo.Demo.demo()")
    public void myThrow(){

        System.out.println("註解---異常");
    }
}

小案例

需求:
這裡寫圖片描述
匯入包:
aopalliance.jar
asm-3.3.1.jar
aspectjweaver.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
commons-logging-1.1.3.jar
javassist-3.17.1-GA.jar
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
mybatis-3.2.7.jar
mybatis-spring-1.2.3.jar
mysql-connector-java-5.1.30.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
spring-aop-4.1.6.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar
spring-jdbc-4.1.6.RELEASE.jar
spring-tx-4.1.6.RELEASE.jar
spring-web-4.1.6.RELEASE.jar

資料庫根據實體類去建立
相關程式碼:
Src:
com.bjsxt.advice:
MyAfter.java:

package com.bjsxt.advice;

import java.lang.reflect.Method;
import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice;

public class MyAfter implements AfterReturningAdvice{

    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        //建立日誌物件
                Logger logger=Logger.getLogger(MyBefore.class);
        //校驗
                if(arg0!=null){
                    logger.debug(arg2[0]+"在"+new Date().toLocaleString()+"登陸成功");
                }else{
                    logger.debug("查無此人:"+arg2[0]+":登陸失敗");
                }

    }

}

MyBefore.java:

package com.bjsxt.advice;

import java.lang.reflect.Method;
import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;

public class MyBefore implements MethodBeforeAdvice{

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        //建立日誌物件
        Logger logger=Logger.getLogger(MyBefore.class);
        //輸出日誌
        logger.debug(arg1[0]+"在"+new Date().toLocaleString()+"點進行了登陸請求");

    }

}

com.bjsxt.mapper:
UserMapper.java:

package com.bjsxt.mapper;

import com.bjsxt.pojo.User;

public interface UserMapper {

    //查詢使用者資訊---登入功能
    User selUser(String uname,String pwd);

}

UserMapper.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjsxt.mapper.UserMapper">
    <!--根據使用者名稱和密碼查詢使用者資訊  -->
    <select id="selUser" resultType="com.bjsxt.pojo.User" > 
        select * from t_user where uname=#{0} and pwd=#{1}
    </select>   
</mapper>

com.bjsxt.pojo:
User.java:

package com.bjsxt.pojo;

public class User {
    private int uid;
    private String uname;
    private String pwd;
    private String uphone;
    public int getUid() {
        return uid;
    }
    public void setUid(int uid) {
        this.uid = uid;
    }
    public String getUname() {
        return uname;
    }
    public void setUname(String uname) {
        this.uname = uname;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    public String getUphone() {
        return uphone;
    }
    public void setUphone(String uphone) {
        this.uphone = uphone;
    }
    @Override
    public String toString() {
        return "User [uid=" + uid + ", uname=" + uname + ", pwd=" + pwd + ", uphone=" + uphone + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((pwd == null) ? 0 : pwd.hashCode());
        result = prime * result + uid;
        result = prime * result + ((uname == null) ? 0 : uname.hashCode());
        result = prime * result + ((uphone == null) ? 0 : uphone.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (pwd == null) {
            if (other.pwd != null)
                return false;
        } else if (!pwd.equals(other.pwd))
            return false;
        if (uid != other.uid)
            return false;
        if (uname == null) {
            if (other.uname != null)
                return false;
        } else if (!uname.equals(other.uname))
            return false;
        if (uphone == null) {
            if (other.uphone != null)
                return false;
        } else if (!uphone.equals(other.uphone))
            return false;
        return true;
    }
    public User() {
        super();
        // TODO Auto-generated constructor stub
    }
    public User(int uid, String uname, String pwd, String uphone) {
        super();
        this.uid = uid;
        this.uname = uname;
        this.pwd = pwd;
        this.uphone = uphone;
    }



}

com.bjsxt.service:
UserService.java:

package com.bjsxt.service;

import com.bjsxt.pojo.User;

public interface UserService {

    /**
     * 查詢使用者資訊
     * @param uname 使用者名稱
     * @param pwd   密碼
     * @return      返回儲存了使用者資訊的User物件
     */
    User selUserService(String uname,String pwd);
}

com.bjsxt.serviceImpl:
UserServiceImpl.java:

package com.bjsxt.serviceImpl;

import com.bjsxt.mapper.UserMapper;
import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;

public class UserServiceImpl implements UserService {
    // 宣告mapper介面屬性
    private UserMapper um;

    public UserMapper getUm() {
        return um;
    }

    public void setUm(UserMapper um) {
        this.um = um;
    }
    //查詢使用者資訊---登入功能
    @Override
    public User selUserService(String uname, String pwd) {
        return um.selUser(uname, pwd);
    }

}

com.bjsxt.servlet:
UserServlet.java:

package com.bjsxt.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.bjsxt.pojo.User;
import com.bjsxt.service.UserService;

/**
 * Servlet implementation class UserServlet
 */
@WebServlet("/us")
public class UserServlet extends HttpServlet {
    //宣告業務層物件
        private UserService us;
    //初始化
        @Override
        public void init() throws ServletException {
            //獲取Spring容器物件
            ApplicationContext ac=WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
            //給業務層物件賦值
            us=(UserService) ac.getBean("us");
        }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //設定請求編碼格式
        req.setCharacterEncoding("utf-8");
        //設定響應編碼格式
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        //獲取請求資訊
        String uname=req.getParameter("uname");
        String pwd=req.getParameter("pwd");
        //處理請求資訊
            //獲取業務層物件
            User u=us.selUserService(uname, pwd);
        //響應處理結果
            if(u!=null){
                resp.sendRedirect("main.jsp");
            }else{
                req.getRequestDispatcher("login.jsp").forward(req, resp);
            }
    }

}

applicationcontext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--  配置資料來源-->
            <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
                <property name="username" value="root"></property>
                <property name="password" value="1234"></property>
            </bean>
        <!--  配置工廠-->
            <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
        <!-- 配置mapper掃描 -->
            <bean id="mapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                <property name="basePackage" value="com.bjsxt.mapper"></property>
                <property name="sqlSessionFactory" ref="factory"></property>
            </bean>
        <!--配置其他bean  -->
            <!--配置業務bean  -->
                <bean id="us" class="com.bjsxt.serviceImpl.UserServiceImpl">
                    <property name="um" ref="userMapper"></property>
                </bean>
            <!--配置通知bean  -->
                <bean id="before" class="com.bjsxt.advice.MyBefore"></bean>
                <bean id="after" class="com.bjsxt.advice.MyAfter"></bean>
            <!--配置切面  -->
                <aop:config>
                    <aop:pointcut expression="execution(* com.bjsxt.serviceImpl.UserServiceImpl.selUserService(..))" id="my"/>
                    <aop:advisor advice-ref="before" pointcut-ref="my"/>
                    <aop:advisor advice-ref="after" pointcut-ref="my"/>
                </aop:config>

</beans>

log4j.properties:


log4j.rootCategory=info



log4j.logger.com.bjsxt.mapper=debug, CONSOLE
log4j.logger.com.bjsxt.advice=debug, CONSOLE

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n


log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n

WebContent:
login.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <form action="us" method="get">
        使用者名稱:<input type="text"  name="uname" value=""/><br />
        密碼:<input type="password"  name="pwd"/><br />
        <input type="submit" value="提交" />
    </form>
</body>
</html>

WEB-INF:
web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
     <!--配置Spring配置檔案路徑  -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationcontext.xml</param-value>
        </context-param>
     <!--配置監聽器  -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
</web-app>

原始碼地址:
連結:https://pan.baidu.com/s/1n31EHGehJi8TqvImoJM2bw 密碼:gl6b

代理模式

其他連結
https://blog.csdn.net/cckevincyh/article/details/54962920
https://blog.csdn.net/u013126379/article/details/52121096

代理設計模式:
    靜態代理設計模式:
            真實類:要進行功能擴充套件的類
            代理類:進行功能擴充套件的類
            介面:真實類和代理類都要實現
                代理流程:
                代理類和真實類必須實現同一個介面
                在代理類中呼叫真實類的方法,並完成功能擴充套件
                修改呼叫方法為呼叫代理類
            缺陷:
                代理類又程式設計師自己編寫。
            優點:
                擴充套件真實類的功能
                讓真實類的方法功能更加明確。
                保護真實物件
    動態代理設計模式:    
            特點:
                動態生成代理物件。
            JDK動態代理:    基於 介面
                第一步:建立一個實現InvocationHandler介面的java類
                      並實現invoke方法
                    引數:
                        Object arg0:表示動態產生的代理物件
                        Method arg1:表示真實方法的Method物件
                        Object[] arg2:表示接收的實參
                    注意:
                        寫的是功能擴充套件程式碼。
                第二步:
                    使用Proxy物件動態建立代理物件:
                        Proxy.newProxyInstance(TestBoss.class.getClassLoader(),new Class[]{Gongneng.class},new TestJdk());
                        使用返回值呼叫介面方法完成業務處理即可
                    注意:
                        該方法返回的是代理物件。

                特點:
                    動態的產生代理物件
                    基於介面的,代理物件和真實物件需要實現相同的介面
                    不用匯入jar包
                    基於反射,效率低下
        cglib動態代理   :基於繼承
第一步:
        建立一個實現了MethodInterceptor介面的java類
        實現介面方法:
        @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
        System.out.println("你預約了嗎?");
        arg1.invoke(new Boss(), arg2);
        System.out.println("記錄吃飯記錄");
        return null;
    }       
    Object arg0, 代理物件
    Method arg1,   真實方法物件
    Object[] arg2, 引數
                    MethodProxy arg3    代理方法物件

            第二步:動態獲取代理物件
                Enhancer en=new Enhancer();
            en.setSuperclass(Boss.class);//宣告要繼承的實現類
            en.setCallback(new  TestCglib());
            Boss b2=(Boss)en.create();
            b2.eat();
            第三步:使用代理物件完成功能處理
            特點:
                基於繼承的,效率較高
                需要匯入jar包






小結

Spring Aop概念學習
Schema-based方式
基於AspectJ方式
使用註解(基於AspectJ)
小案例
代理模式

相關文章