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)