spring註解、aop(二)

使用註解配置springjava

  1.導入 spring-aop-5.0.6.RELEASE.jar包web

  2.爲主配置文件引入新的命名空間 xmlns:context="http://www.springframework.org/schema/context"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: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/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--指定掃描com.david.bean下的全部包全部類中的註解 -->
    <context:component-scan base-package="com.david.bean"></context:component-scan>

</beans>

  3.在類中使用註解express

@Component("user")
//至關於<bean name="user" class="com.david.bean.User" />
public class User {
    private String name;
    private Integer age;
    private Car car;

    ...
}

註解後來又出現了三種,能夠體現層級關係編程

@Component("user")
@Service("user") //service層
@Controller("user") //web層
@Repository("user") //dao層

指定做用範圍框架

@Component("user")
//至關於<bean name="user" class="com.david.bean.User" />
@Scope(scopeName = "prototype")
//至關於<bean name="user" class="com.david.bean.User" scope="prototype"></bean>

值類型注入oop

public class User {
    @Value("david") //字段注入 破壞了封裝性
    private String name;
    private Integer age;
    private Car car;

    @Value("18") //set方法注入 推薦使用
    public void setAge(int age) {
        this.age = age;
    }
    ...
}

引用類型(對象)注入測試

@Component("car")
public class Car {
    @Value("奧拓")
    private String name;
    @Value("red")
    private String color;
    ...
}
@Component("user")
public class User {
    @Autowired //自動裝配 對象注入
    private Car car;
    ...
}

@autowired 自動裝配的方式 若是匹配到多個類型一致的對象,沒法選擇具體注入哪個對 如:this

    <bean name="car2" class="com.david.bean.Car">
        <property name="name" value="奧迪"></property>
        <property name="color" value="black"></property>
    </bean>

此時須要使用@Qualifier("car2")註解告訴容器具體注入哪一個對象 和@autowired一塊兒使用spa

    @Autowired
    @Qualifier("car2")
    private Car car;

上面這種要使用兩個註解,還有一個註解@Resource 能夠手動指定注入哪一個對象 

    @Resource(name="car2") //手動指定
    private Car car;

 

初始化和銷燬

public class User {
    ...
    @PostConstruct //至關於init-method 對象建立後調用
    public void init(){
        System.out.println("init");
    }

    @PreDestroy //銷燬前調用 至關於destory-method
    public void destory(){
        System.out.println("destory");
    }
    ...
}

 

aop:面向切面編程,是對oop面向對象編程的補充和完善。

spring中的aop

  spring可以爲容器中管理的對象生成動態代理對象。

spring實現aop的原理

  1.動態代理(優先使用)

    被代理對象必需要實現接口,才能產生代理對象,若是沒有接口將不能使用動態代理技術

  2.cglib代理(沒有接口時)

    第三方代理技術,能夠對任何類生成代理對象。代理的原理是對目標對象進行繼承代理

spring AOP 名詞解釋:

  1.Joinpoint鏈接點:目標對象中,全部能夠加強的方法。(能夠加強的方法)如:UserServiceImpl implements UserService 中實現的方法 save() delete()

  2.Pointcut切入點:目標對象中,已經加強的方法。(已加強的方法)如:已經過代理加強的save() 或delete() 能夠單獨指定某些加強或不加強。

  3.Advice通知/加強:須要加強的代碼。(代理對象調用目標方法先後執行的代碼)如://前加強 method.invoke(us,arg) //後加強。

  4.Target目標對象:被代理對象。如UserServiceImpl。

  5.Weaving織入:將通知織入(應用到)切入點的過程。

  6.Proxy代理:將通知織入道目標對象以後,造成代理對象。

因此進行AOP編程的關鍵就是定義切入點和定義加強處理,一旦定義了合適的切入點和加強處理,AOP框架將自動生成AOP代理,即:代理對象的方法=加強處理+被代理對象的方法。

基於spring的aop實現

1.導包 aopalliance.jar aspectjweaver.jar  spring aop須要這兩個包的支持 下載地址:

http://www.java2s.com/Code/Jar/a/Downloadaopalliancejar.htm

http://www.java2s.com/Code/Jar/a/Downloadaspectjweaverjar.htm

2.準備目標對象

  先定義一個接口

public interface IHelloWorld {
    void printHelloWorld();
    void doPrint();
}

  在定義兩個接口實現類

public class HelloWorldImpl1 implements IHelloWorld
{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }

    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return ;
    }
}

public class HelloWorldImpl2 implements IHelloWorld{
    public void printHelloWorld()
    {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }

    public void doPrint()
    {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return ;
    }
}

3.準備通知

package com.david.bean;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {
    //前置通知-目標方法調用以前調用
    public void before() {
        System.out.println("前置通知");
    }

    //後置通知-目標方法以後調用,若是異常不會調用
    public void afterRuning() {
        System.out.println("後置通知,出現異常不會調用");
    }

    //環繞通知-在目標方法以前和以後都調用
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("環繞前通知");
        Object proceed = pjp.proceed();//調用目標方法
        System.out.println("環繞後通知");
    }

    //異常通知-若是出現異常就會被調用
    public void afterException(){
        System.out.println("出現異常");
    }

    //後置通知-目標方法以後調用,不管異常與否都會調用
    public void after() {
        System.out.println("後置通知,不管異常與否都會調用");
    }
}

4.配置進行織入,將通知織入目標對象中

新建一個aop.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--導入aop命名空間 -->
<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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
    <!--配置目標對象 -->
    <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" />
    <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" />
    <!--配置通知對象 -->
    <bean id="myAdvice" class="com.david.bean.MyAdvice" />
    <!--配置將通知織入目標對象 -->
    <aop:config>
        <!--配置切入點:全部方法都加強 -->
        <aop:pointcut id="allMethod" expression="execution(* com.david.bean.IHelloWorld.*(..))"></aop:pointcut>
        <aop:aspect id="advice" ref="myAdvice">
            <!--通知方法 -->
            <aop:before method="before" pointcut-ref="allMethod" />
            <aop:after-returning method="afterRuning" pointcut-ref="allMethod"></aop:after-returning>
            <aop:around method="around" pointcut-ref="allMethod"></aop:around>
            <aop:after method="after" pointcut-ref="allMethod" />
        </aop:aspect>
    </aop:config>
</beans>

5.編寫測試類

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("aop.xml");

        IHelloWorld hw1 = (IHelloWorld)ac.getBean("helloWorldImpl1");
        IHelloWorld hw2 = (IHelloWorld)ac.getBean("helloWorldImpl2");
        hw1.printHelloWorld();
        System.out.println();
        hw1.doPrint();

        System.out.println();
        hw2.printHelloWorld();
        System.out.println();
        hw2.doPrint();
    }

 

使用spring aop開發 就不須要咱們手寫動態代理代碼了,還封裝了cglib代理。能夠對任何類進行代理加強。

 

spring的aop註解配置

<?xml version="1.0" encoding="UTF-8"?>
<!--導入aop命名空間 -->
<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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
    <!--配置目標對象 -->
    <bean id="helloWorldImpl1" class="com.david.bean.HelloWorldImpl1" />
    <bean id="helloWorldImpl2" class="com.david.bean.HelloWorldImpl2" />
    <!--配置通知對象 -->
    <bean id="myAdvice" class="com.david.bean.MyAdvice" />

    <!--開啓使用註解織入目標對象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

通知類 使用註解設置

@Aspect //表示該類是一個通知類
public class MyAdvice {
    @Before("execution(* com.david.bean.IHelloWorld.*(..))") //是一個前置通知並指定切入點
    public void before() {
        System.out.println("前置通知");
    }
    @After("execution(* com.david.bean.IHelloWorld.*(..))")
    public void after() {
        System.out.println("後置通知,不管異常與否都會調用");
    }

    @AfterReturning("execution(* com.david.bean.IHelloWorld.*(..))")
    public void afterRuning() {
        System.out.println("後置通知,出現異常不會調用");
    }

    @Around("execution(* com.david.bean.IHelloWorld.*(..))")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("環繞前通知");
        Object proceed = pjp.proceed();//調用目標方法
        System.out.println("環繞後通知");
    }

}

再次運行 效果同樣的。 抽取切入點

package com.david.bean;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect //表示該類是一個通知類
public class MyAdvice {
    //定義一個切入點規則
    @Pointcut("execution(* com.david.bean.IHelloWorld.*(..))")
    public void pc(){

    }

    @Before("MyAdvice.pc()")
    public void before() {
        System.out.println("前置通知");
    }
    @After("MyAdvice.pc()")
    public void after() {
        System.out.println("後置通知,不管異常與否都會調用");
    }

    @AfterReturning("MyAdvice.pc()")
    public void afterRuning() {
        System.out.println("後置通知,出現異常不會調用");
    }

    @Around("MyAdvice.pc()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("環繞前通知");
        Object proceed = pjp.proceed();//調用目標方法
        System.out.println("環繞後通知");
    }

}
相關文章
相關標籤/搜索