天天看點

spring之ioc及aop程式設計

1.spring的jar包下載下傳

2.在src下建立一個檔案夾resources,放個配置檔案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"

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="tcc"></context:component-scan>

<!-- <context:component-scan base-package="tcc.test.springioc"></context:component-scan> -->

<!-- 确定 AOP注解生效 -->

<!-- <aop:aspectj-autoproxy />有一個proxy-target-class屬性,預設為false,表示使用jdk動态代理織入增強,

當配為<aop:aspectj-autoproxy poxy-target-class="true"/>時,表示使用CGLib動态代理技術織入增強。

不過即使proxy-target-class設定為false,如果目标類沒有聲明接口,則spring将自動使用CGLib動态代理。 -->

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

</beans>

3.寫個ioc測試類

package tcc.test.springioc;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

@SuppressWarnings("resource") //抑制警告,打斷點不影響

public static void main(String[] args) {

ApplicationContext ac = new ClassPathXmlApplicationContext("resources/applicationContext.xml");

Student student = ac.getBean("student", Student.class);

student.eat();

}

}

測試bean

import org.springframework.context.annotation.Scope;

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Service;

@Scope("prototype")

//singleton 表示在spring容器中的單例,通過spring容器獲得該bean時總是傳回唯一的執行個體

//prototype表示每次獲得bean都會生成一個新的對象

//request表示在一次http請求内有效(隻适用于web應用)

//session表示在一個使用者會話内有效(隻适用于web應用)

//globalSession表示在全局會話内有效(隻适用于web應用)

//在多數情況,我們隻會使用singleton和prototype兩種scope,如果在spring配置檔案内未指定scope屬性,預設為singleton。

@Component("student")//類注解

public class Student {

public void eat(){

System.out.println("Student類新增了");

}

Spring的IOC有三種注入方式 :構造器注入、setter方法注入、根據注解注入。

BeanFactory和ApplicationContext有什麼差別?

        BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring裡面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、執行個體化,控制bean的生命周期,維護bean之間的依賴關系。ApplicationContext接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的架構功能:

(2)①BeanFactroy采用的是延遲加載形式來注入Bean的,即隻有在使用到某個Bean時(調用getBean()),才對該Bean進行加載執行個體化。這樣,我們就不能發現一些存在的Spring的配置問題。如果Bean的某一個屬性沒有注入,BeanFacotry加載後,直至第一次使用調用getBean方法才會抛出異常。

  ②ApplicationContext,它是在容器啟動時,一次性建立了所有的Bean。這樣,在容器啟動時,我們就可以發現Spring中存在的配置錯誤

BeanFactory需要手動注冊,而ApplicationContext則是自動注冊。

Spring架構中的單例Beans是線程安全的麼?

   Spring架構并沒有對單例bean進行任何多線程的封裝處理。如果你的bean有多種狀态的話(比如 View Model 對象),就需要自行保證線程安全。最淺顯的解決辦法就是将多态bean的作用域由“singleton”變更為“prototype”。

9、Spring如何處理線程并發問題?

在一般情況下,隻有無狀态的Bean才可以在多線程環境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域,因為Spring對一些Bean中非線程安全狀态采用ThreadLocal進行處理,解決線程安全問題。

ThreadLocal和線程同步機制都是為了解決多線程中相同變量的通路沖突問題。同步機制采用了“時間換空間”的方式,僅提供一份變量,不同的線程在通路前需要擷取鎖,沒獲得鎖的線程則需要排隊。而ThreadLocal采用了“空間換時間”的方式。

ThreadLocal會為每一個線程提供一個獨立的變量副本,進而隔離了多個線程對資料的通路沖突。因為每一個線程都擁有自己的變量副本,進而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。

建立對象的時機

          1、在預設的情況下,通過xml配置的在spring容器啟動的時候建立對象

                   在spring配置檔案中,隻要根據以上的三種方式的其中一種配置了,spring容器就會建立對象

                   好處:spring容器和web容器整合的時候,當web容器啟動的時候就可以初始化spring容器了,如果這個時候

                           spring容器内部有錯誤,則直接會報錯

                   如果該bean中存放着大量的資料,而且資料的初始化發生在建立對象的時候,這個時候,資料會過早的駐留在記憶體中

          2、如果在spring的配置檔案中一個bean的配置中有lazy-init="true",那麼該bean在調用getBean方法時建立對象

                   不好處:不能過早的發現錯誤

                   好處:按照需求加載資料(什麼時候要什麼時候加載)

<bean id="ms1" class="basic.MassageService" init-method="in" destroy-method="des"/>

各種對象,都是在tomcat啟動時建立,Tomcat怎麼知道的?

tomcat啟動時  會把每一個項目的所有代碼掃描一遍,需要它啟動時就建立的,就建立對象。

Tomcat在啟動時都建立了哪些對象?慢慢總結如下:

servletContext(一個項目的全局變量)、Servlet(load-on-startup為非負數時)、Filter(整個項目的過濾器)

寫個aop測試類

1.

package tcc.test.springaop;

@SuppressWarnings("resource")

Person person = ac.getBean("person", Person.class);

person.add();//調用一次MyAspectJ類

person.update();//調用一次MyAspectJ類

person.delete();//調用一次MyAspectJ類

2.

public interface Person {

public void add();

public void update();

public void delete();

3.

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;

import tcc.test.springioc.Student;

@Component("person")//類注解

public class PersonImple implements Person {

/**

* @desc 實作接口方法

*/

@Autowired //預設按類型裝bai配(這個注解是屬業spring的)

Student student;

@Resource //這個注解屬于J2EE的),預設按照名稱進行裝配

Student student2;

public void add() {

student2.eat();

student.eat();

System.out.println("add()方法執行了.....");//3

int i = 1/0;

@Override

public void update() {

System.out.println("update()方法執行了.....");

// int i = 1/0;

public void delete() {

System.out.println("delete()方法執行了.....");

4.

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

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.aspectj.lang.annotation.Pointcut;

@Component//類注解

@Aspect//AspectJ注解

public class MyAspectJ {

//聲明公共切入點

@Pointcut("execution(* tcc.test.springaop.PersonImple.*(..))")

public void myPointcut() {

//前置通知注解,隻有一個參數時,value可以省略不寫

@Before("execution(* tcc.test.springaop.PersonImple.*(..))")

public void myBefort(JoinPoint joinPoint) {

System.out.println("前置通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName());//2:會去調用具體的方法

//後置通知注解,當參數大于1時,value必須寫

@AfterReturning(value="myPointcut()", returning="ret")

public void myAfterReturning(JoinPoint joinPoint, Object ret) {

System.out.println("後置通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName()//4

+ ", ret: " + ret);

//環繞通知注解

@Around("myPointcut()")

public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable {

System.out.println("環繞通知====前>>>>>>>>>>>");

Object obj = joinPoint.proceed();//1

System.out.println("環繞通知====後<<<<<<<<<<<");

return obj;

//異常通知注解:出現異常後調用

@AfterThrowing(value="myPointcut()", throwing="e")

public void myThrowint(JoinPoint joinPoint, Throwable e) {

System.out.println("異常通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName() //4

+ ", e: " + e.getMessage());

System.exit(0);

//最終通知注解

@After("myPointcut()")

public void myAfter(JoinPoint joinPoint) {

System.out.println("最終通知>>>>>>>>>joinPoint: " + joinPoint.getSignature().getName());//3

執行順序:環繞通知注解@Around("myPointcut()")——》前置通知注解@Before("execution(* tcc.test.springaop.PersonImple.*(..))")——》最終通知注解@After("myPointcut()")——》異常通知注解:出現異常後調用@AfterThrowing(value="myPointcut()", throwing="e")或者後置通知注解@AfterReturning(value="myPointcut()", returning="ret")

Spring AOP中的動态代理主要有兩種方式,JDK動态代理和CGLIB動态代理:

        ①JDK動态代理隻提供接口的代理,不支援類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 通過invoke()方法反射來調用目标類中的代碼,動态地将橫切邏輯和業務編織在一起;接着,Proxy利用 InvocationHandler動态建立一個符合某一接口的的執行個體,  生成目标類的代理對象。實作的方式做的動态代理

 ②如果代理類沒有實作 InvocationHandler 接口,那麼Spring AOP會選擇使用CGLIB來動态代理目标類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運作時動态的生成指定類的一個子類對象,并覆寫其中特定方法并添加增強代碼,進而實作AOP。CGLIB是通過繼承的方式做的動态代理,是以如果某個類被标記為final,那麼它是無法使用CGLIB做動态代理的。

 InvocationHandler 的 invoke(Object  proxy,Method  method,Object[] args):proxy是最終生成的代理執行個體;  method 是被代理目标執行個體的某個具體方法;  args 是被代理目标執行個體某個方法的具體入參, 在方法反射調用時使用。

spring之ioc及aop程式設計