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 是被代理目标執行個體某個方法的具體入參, 在方法反射調用時使用。
