1. 程式人生 > 實用技巧 >Spring5複習IOC與AOP

Spring5複習IOC與AOP

1.AOP:控制反轉,把建立物件的過程交給Spring容器

2.IOC:面向切面程式設計,不改原始碼進行功能增強

bean.xml檔案

<bean id = "暱稱" class = "類的全類名" ></bean>

測試

1.載入spring配置檔案
ApplicationContext  context  = new ClassPathXmlApplicationContext("bean.xml");//src下的可以直接這樣掃描
2.得到配置的物件
  類名 暱稱= context.getBean("bean中ID",類名.class);

3.呼叫bean中物件類中的方法
  暱稱.method();

IOC容器:

(1)IOC底層原理

(2)IOC介面(BeanFactory)

(3)IOC操作Bean管理(註解與xml)

控制反轉-->物件的建立與物件排程都交給spring管理

(1):...

------> 原始模式(耦合度高)

------>工廠模式

------>IOC過程

IOC(介面)

IOC思想基於IOC容器,底層是物件工廠

Spring提供IOC容器實現的兩種方式(兩個介面)載入配置檔案,獲取配置建立物件

(1)BeanFactory:spring內建介面,不提供給開發人員使用。

載入配置檔案時 不建立物件,獲取(使用)物件的時候才會建立物件----getBean("");

(2)ApplicationContext:上面的子介面,功能更強,開發人員使用

載入即建立。

(3)ApplicationContext介面的實現類

IOC操作Bean管理

(1)xml

(2)註解

建立物件時預設執行無參構造方法

xml方式注入屬性:

(1)DI:依賴注入(ioc的一種具體實現)

1. set方法注入:

//在類中生成set方法

<bean id = "" class =""> <!-- name:類中屬性名稱 value:向屬性中注入的值 --> <property name = "" value =""></property> </bean>

2. 有參注入:

//在類中生成有參構造方法

<bean id ="" class = ""> <constructor-arg name = "" value =""> </contructor-arg> </bean>

p 名稱空間注入

(1)用於簡化xml配置

  //新增p名稱空間
  xmlns:p="http://www.springframework.org/schema/p"
  //set注入屬性
  <bean id = "" class = "" p:屬性名 = "屬性值" >
 
 </bean>

xml注入其他型別:

null<property name ="">
    <null/>
  </property>


特殊符號:
    <property name ="" >
    <value>
     < <![CDATA[****]]>>

     </value>
     </property>

注入屬性-外部bean

(1)建立兩個類 service 和 mapper

(2) service 呼叫 mapper

<!-- ref 就是將外部的bean注入進來-->

注入屬性-內部bean和級聯賦值

(1)一對多

(2)實體類中表示一對多關係

<!-- emp 物件-->
<bean id = "emp" class = "">
<!-- emp的屬性和dept物件屬性--> <property name = "" value = ""> </property> <property name = "dept" > <bean id = "dept" class = "">
<property name = "" value = ""></property>
</bean> <property>
</bean>

---------------------------------------------------內部bean

注入屬性-級聯賦值1

<!-- emp 物件-->
<bean id  = "emp" class = "">
<!-- emp的屬性和dept物件屬性-->
    <property name = "" value = ""> </property>
    <property name = "dept" ref = "dept"></property>
<!--外部bean 級聯賦值-->
</bean>
        <bean id = "dept" class = "">
              <property name  = "" value = ""><property>
 </bean>

注入屬性-級聯賦值2(猜測比外部級聯優先順序高)

<!-- emp 物件 生成一下getDept方法-->
<bean id  = "emp" class = "">
<!-- emp的屬性和dept物件屬性-->
    <property name = "" value = ""> </property>
    <property name = "dept" ref = "dept"></property>
     <property name = "dept.dname" value= ""></property>
<!--外部bean 級聯賦值-->
</bean>
        <bean id = "dept" class = "">
              <property name  = "" value = ""><property>
 </bean>

xml注入集合屬性:

<!-- 陣列-->
<bean ...>
    <property name = "course">
     <array>
        <value>...</value>
                 ......
        </array>
    </property>     

<!-- map -->

    <property name = "maps">
     <map>
        <entry key = "" value = ""> </entry>
                 ......
        </map>
    </property>     

<!-- list-->

    <property name = "list">
     <list>
        <value>...</value>
                 ......
        </list>
    </property>     

<!-- set-->

    <property name = "list">
     <set>
        <value>...</value>
                 ......
        </set>
    </property>     

注入集合物件2

<!-- 注入list集合型別 ,值是物件-->
<property name = "courseList">
          <list>
           <ref bean = "" ></ref>
           </list>
  </property>


<!--建立多個course物件-->
<bean 1>
<property/>
....
<bean 2>
<property/>
....

把集合注入部分提取出來:

引入名稱空間util

<util:list id = "bookList">
    <value></value>
    <value></value>
</util:list>



<bean id  = "book " class = "">
   <property name = '"'  ref = "bookList"></>
</>

IOC操作bean管理(FactoryBean)

1. 普通bean

2.FactoryBean (定義bean型別與返回型別可以不同)

第一步 :建立類 ,作為工廠bean ,實現FactoryBean 。

第二步 :實現接口裡面的方法,在實現方法中定義返回的bean型別

public class MyBean implements FactoryBean<Course>{
       //定義返回Bean
       public Course getObject () throws Exception{
                    new Course();-->course
                            course.setCname("....");
                                  return course;
      }
          public Class<?> getObjectType() {
               return null;

           }
         public boolean isSingleton () {
                     return false;
         
    }
           

}
--------------------------------------------------------------------
<bean id = "myBean" class = ""></bean>
.....

context.getBean("myBean", Course.class); --->course

bean的作用域:

通過scope屬性的值來設定:

scope = "singleton"(預設) 載入配置檔案時就會建立單例項物件

prototype:多實呼叫getBean方法時建立多例項物件

request:一次請求

session:一次會話

bean的生命週期:

(1)無參構造建立bean例項

(2)為bean的屬性設定值,對其他bean的引入(呼叫set方法)

(3)把bean例項傳遞給bean後置處理器postProcessBeforeInitialization方法

(3)呼叫bean的初始化的方法

(4)把bean例項傳遞給bean後置處理器postProcessAfterInitialization方法

(4)使用bean

(5)容器關閉時,呼叫bean的銷燬方法。

//在類中建立初始化方法 init () 和 銷燬方法 destroy()
<bean id  =  "" class  = "" init-method = "init " destroy-method = "destroy"> 
<property></>
</bean>
..........
contex.close();
ApplicationContext介面中沒有close方法
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ();

新增後置處理器:

(1)建立類 MyBeanPost,實現BeanPostProcessor介面

(2)實現其中兩個方法

<!-- 配置後置處理器  為配置檔案中所有bean例項建立後置處理器-->
<bean id  = "myBeanPost" class = "....MyBeanPost">

xml自動裝配:

根據指定裝配規則(屬性名稱 屬性型別),Spring指定將匹配的屬性值進行注入

autowire = "byName";byType;

byName 注入值bean得id值與類的屬性名稱一致

外部屬性檔案:

1.建立外部屬性檔案

2. 在配置檔案中新增context名稱空間

<!-- 引入外部檔案-->
<context:property-placeholder location ="classpath:jdbc.properties" >
<!-- 配置連線池-->
<bean id="dataSource"class="com.alibaba.druid.pool.DruidDataSource">
  <property name = "driverClassName" value"${prop.driverClass}"></property>
.....
</bean>

IOC註解

Spring針對bean管理中建立物件提供的註解:

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

基於註解實現物件建立

第一步 引入依賴

第二步 開啟元件掃描<context>

多個包之間 逗號隔開(掃描上層目錄也行)

<context:component-scan base-package = " "></context:component-scan>

第三步 建立類 在類上添加註解

//自定義配置filter
<context : component-scan base-package = "" use-default-filters = "false">
<context : include-filter type = "annotation" expression = "org.springframework.stereotype.Controller"/>
</>
exclude-filter type 不掃描哪些內容

註解實現屬性注入:

(1)@AutoWired :根據屬性型別注入

(2)@Qualifier:根據屬性名稱注入

根據型別注入,一個藉口可能有多個實現類,可以在AutoWired 下新增Qualifier(value ="userDaoImpl1")

(3)@Resource:都行

如果要根據名稱注入 Resource(name = "")

(4)@Value:注入普通型別屬性

為定義的屬性賦值

service中定義dao型別屬性,是由於spring的設計思想是利用java的多型特性 減少耦合

完全註解開發:

配置類:SpringConfig

@Configuration

@Component(basePackages ={""})

SpringConfig

載入配置類

new AnnotationConfigApplicationContext(SpringConfig.class);-->ApplicationContext

AOP(底層動態代理)

不改原始碼,增加新功能

動態代理:

(1)有介面:建立介面實現類代理物件,增強類方法

(2)沒有介面:建立類的子類代理物件

1.JDK動態代理,使用Proxy類裡面的方法建立代理物件

呼叫nexProxyInstance方法

引數一:類載入器

引數二:增強方法所在的類,這個類實現的介面,支援多個介面

引數三:實現這個介面InvocationHandler,建立代理物件,寫增強部分的程式碼

public class JDKProxy{
   psvm{
<!-- 建立介面實現類代理物件-->
            Class [] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
      Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new InvocationHandler(){
public Object invoke (Object proxy,Method method,Object[] args) throws Throwable{
     return null;
}
}
);
-------------------------------------------------------------------------
UserDao dao 
=Proxy.newProxyInstance(JDKProxy.class.getClassLoader(),interfaces,new UserDapProxy(userDao) );




    }
}

//建立代理物件程式碼
class UserDaoProxy implements InvocationHandler{
//把建立的是誰的代理物件,就把誰傳遞過來
//有參構造傳遞
  private Object obj;
 public UserDaoProxy(Oject obj){
    this.obj = obj;   
}



  public Object invoke (Object proxy,Method method,Object[] args) throws Throwable{
  
   Onject  res  =  method.invoke(obj,args);
     return res;
}
}

Aop(術語)

1.連線點:可以被增強的方法

2.切入點:實際被增強的方法

3.通知(增強):增加的部分邏輯

前置通知 後置通知 環繞通知 異常通知 最終通知

4.切面

把通知應用到切入點的過程

基於AspectJ實現AOP操作

獨立的AOP框架

切入點表示式

作用:知道哪個類裡面的哪個方法進行增強

execution([許可權修飾符] [返回型別][全類名][方法名稱]([引數列表]))

AspectJ註解

(1)xml中新增context,aop名稱空間,開啟註解掃描

(2)使用註解建立User和UserProxy物件

(3)增強類上加註解@Aspect 生成代理物件

(4)開啟Aspect生成代理物件

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

@Component
@Aspect
public class UserProxy{
//前置通知 @Before(value
= "execution(*org.xxx.User.add(..))") public void before(){ System.out.println("...."); } }
@After(value = "")最終通知
@AfterReturning(value = "")後置通知 (返回通知)有異常不執行
@Around(value = "")環繞通知 引數為 ProceedingJoinPoint proceedingJoinPoint
sout 前
proceedingJoinPoint.proceed();
sout 後
@AfterThrowing(value = "")異常通知

抽取相同的切入點

@Pointcut(value = "execution(*org.xxx.User.add(..))")

public void pointdemo(){

}

@Before (value = "pointdemo()")

多個增強類對一個方法進行增強:優先順序

增強類上加一個註解@Order(數值型別放入值)值小優先順序高

配置檔案做AspectJ

<!-- 配置AOP增強-->
 <aop:config>
    <!-- 切入點-->
      <aop:pointcut id = "p" expression = "execution(*org.xxx.Book.Buy(..))"/>
   <!-- 配置切面-->
<aop :aspect ref = "bookProxy">
  <!--增強作用在具體的方法上-->
  <aop:before method = "before"  pointcut-ref = "p" >
 </aop:aspect>
</aop:config>

<bean id ="book" class = ""></>
<bean id  ="bookProxy" class = "">

@EnableAspectJAutoProxy(proxyTargetClass = true)