Spring 的IOC和AOP以及動(dòng)態(tài)代理
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
76套java從入門到精通實(shí)戰(zhàn)課程分享
依賴
class a中使用class b的屬性或者方法, 叫做classa依賴classb
Spring
1. IOC(控制反轉(zhuǎn))
IoC (Inversion of Control) : 控制反轉(zhuǎn), 是一個(gè)理論,概念,思想。
描述的:把對(duì)象的創(chuàng)建,賦值,管理工作都交給代碼之外的容器實(shí)現(xiàn)。
控制: 創(chuàng)建對(duì)象,對(duì)象的屬性賦值,對(duì)象之間的關(guān)系管理。
反轉(zhuǎn): 把容器代替開(kāi)發(fā)人員管理對(duì)象。創(chuàng)建對(duì)象,給屬性賦值。
正轉(zhuǎn):由開(kāi)發(fā)人員在代碼中,使用new 構(gòu)造方法創(chuàng)建對(duì)象, 開(kāi)發(fā)人員主動(dòng)管理對(duì)象。
public static void main(String args[]){
Student student = new Student(); // 在代碼中, 創(chuàng)建對(duì)象。--正轉(zhuǎn)。
}
容器:是一個(gè)服務(wù)器軟件, 一個(gè)框架(spring)
為什么要使用 ioc :
目的就是減少對(duì)代碼的改動(dòng), 也能實(shí)現(xiàn)不同的功能。 實(shí)現(xiàn)解耦合
java中創(chuàng)建對(duì)象有哪些方式:
1. 構(gòu)造方法 , new Student()
2. 反射
3. 序列化
4. 克隆
5. ioc :容器創(chuàng)建對(duì)象
6. 動(dòng)態(tài)代理
ioc的體現(xiàn):
servlet 1: 創(chuàng)建類繼承HttpServelt
2: 在web.xml 注冊(cè)servlet , 使用
<servlet-name> myservlet </servlet-name>
<servelt-class>com.bjpwernode.controller.MyServlet1</servlet-class>
3. 沒(méi)有創(chuàng)建 Servlet對(duì)象, 沒(méi)有 MyServlet myservlet = new MyServlet()
4. Servlet 是Tomcat服務(wù)器它能你創(chuàng)建的。 Tomcat也稱為容器
Tomcat作為容器:里面存放的有Servlet對(duì)象, Listener , Filter對(duì)象
junit : 單元測(cè)試, 一個(gè)工具類庫(kù),做測(cè)試方法使用的。
使用單元測(cè)試
1.需要加入junit依賴。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
2.創(chuàng)建測(cè)試作用的類:叫做測(cè)試類
src/test/java目錄中創(chuàng)建類
3.創(chuàng)建測(cè)試方法
1)public 方法
2)沒(méi)有返回值 void
3)方法名稱自定義,建議名稱是test + 你要測(cè)試方法名稱
4)方法沒(méi)有參數(shù)
5)方法的上面加入 @Test ,這樣的方法是可以單獨(dú)執(zhí)行的。 不用使用main方法
IOC如何創(chuàng)建對(duì)象
1、聲明一個(gè)bean,就是告訴spring要?jiǎng)?chuàng)建某個(gè)類的對(duì)象
id:對(duì)象的自定義名稱,spring就是通過(guò)這個(gè)ID找到對(duì)象
class:類的全路徑名稱
Spring b把創(chuàng)建的對(duì)象放在map集合,
SpringMap.put(id , 對(duì)象)
xml文件 這就創(chuàng)建對(duì)象了
<bean id = "要?jiǎng)?chuàng)建對(duì)象的類名 別名 也可以是一樣的 如:SomeServiceImpl的別名someService" class = "SomeServiceImpl的全路徑名稱" />
一個(gè)測(cè)試類
@Test
public voidtest(){
// 使用spring容器創(chuàng)建對(duì)象
1、指定spring配置文件的名稱
String config = "bean.xml";
2、創(chuàng)建spring容器對(duì)象 ApplicationContext
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
3、從容器中取對(duì)象 getbean(配置文件中bean的id)
SomeService s = (SomeService)ac.getbean("someService");
4、使用spring創(chuàng)建對(duì)象
s.dosome(); // dosome 是SomeService類中的方法
}
如同 SomeServiceImpl s = new SomeServiceImpl();
s.dosome();
IoC的技術(shù)實(shí)現(xiàn)
DI 是ioc的技術(shù)實(shí)現(xiàn),
DI(Dependency Injection) :依賴注入, 只需要在程序中提供要使用的對(duì)象名稱就可以, 至于對(duì)象如何在容器中創(chuàng)建,
賦值,查找都由容器內(nèi)部實(shí)現(xiàn)。
spring是使用的di實(shí)現(xiàn)了ioc的功能, spring底層創(chuàng)建對(duì)象,使用的是反射機(jī)制。
spring是一個(gè)容器,管理對(duì)象,給屬性賦值, 底層是反射創(chuàng)建對(duì)象。
set方法注入
類:
public class Student(){
private String name;
private int age;
private School school; //引用數(shù)據(jù)類型
無(wú)參構(gòu)造函數(shù)
有參的構(gòu)造函數(shù)
private void setName(String name){
this.name = name;
}
private void setAge(int age){
this.age= age;
}
private void setschool(School school){
this.school= school;
}
}
public class School (){
private String name;
無(wú)參構(gòu)造函數(shù)
有參的構(gòu)造函數(shù)
private void setName(String name){
this.name = name;
}
}
Spring 調(diào)用類中的set方法,給參數(shù)注入值
語(yǔ)法:
簡(jiǎn)單類型的set注入
> 1、語(yǔ)法
> > <bean id = "要?jiǎng)?chuàng)建對(duì)象的類名 如:someService" class = "SomeService的全路徑名稱" >
<property name = "參數(shù)名" value="值"/>
</bean>
xml文件
<bean id = "student" class = "Student的全路徑名稱" >
<property name = "name" value="老師"/>
<property name = "age" value="20"/>
</bean>
引用數(shù)據(jù)類型的set注入
2、語(yǔ)法
<bean id = "要?jiǎng)?chuàng)建對(duì)象的類名 如:someService" class = "SomeService的全路徑名稱" >
<property name = "參數(shù)名" ref=" 要引用的對(duì)象的bean的id"/>
</bean>
<bean id = "student" class = "Student的全路徑名稱" >
<property name = "name" value="老師"/>
<property name = "age" value="20"/>
<property name = "school" ref="school"/>
</bean>
<bean id = "school" class = "School的全路徑名稱" >
<property name = "name" value="清華"/>
</bean>
構(gòu)造方法的注入
spring調(diào)用有參構(gòu)造方法。在創(chuàng)建對(duì)象的時(shí)候注入值
語(yǔ)法
<bean id = "要?jiǎng)?chuàng)建對(duì)象的類名 如:someService" class = "SomeService的全路徑名稱" >
<donstructor-arg name = "參數(shù)名" value = "值"/> name :構(gòu)造方法的形參名
或者
<donstructor-arg index= "0" value = "值"/> index 構(gòu)造方法的形參名的位置 0 1 2
或者
value 構(gòu)造方法的形參是簡(jiǎn)單類型的
ref:構(gòu)造方法形參是引用類型
</bean>
<bean id = "student" class = "Student的全路徑名稱" >
<donstructor-arg name = "name" value = "張三"/>
<donstructor-arg name = "age" value = "20"/> name :構(gòu)造方法的形參名
或者
<donstructor-arg index= "0" value = "張三"/> index 構(gòu)造方法的形參名的位置 0 1 2
<donstructor-arg index= "1" value = "20"/>
<donstructor-arg index= "3" ref= "school"/>
ref:構(gòu)造方法形參是引用類型s
</bean>
<bean id = "school" class = "School的全路徑名稱" >
<property name = "name" value="清華"/>
</bean>
引用數(shù)據(jù)類型的自動(dòng)注入
byName
1、byName(按名稱注入):Java類中引用數(shù)據(jù)類型的屬性名和spring容器中(配置文件)引用類性的bean id 名一樣
<bean id = "myStudent" class = "Student的全路徑名稱" autowire = "byName">
基本數(shù)據(jù)類型的賦值
</bean>
<bean id = "myStudent" class = "Student的全路徑名稱" autowire = "byName">
<donstructor-arg name = "name" value = "張三"/>
<donstructor-arg name = "age" value = "20"/> name :構(gòu)造方法的形參名
// <donstructor-arg index= "3" ref= "school"/>
ref:構(gòu)造方法形參是引用類型
</bean>
<bean id = "school" class = "School的全路徑名稱" >
<property name = "name" value="清華"/>
</bean>
byType
byType:按照類型注入
Java類中引用類型的數(shù)據(jù)類型和spring容器中(配置文件)bean 的class 屬性是同源關(guān)系的 如在一個(gè)包下
同源 就是一類的意思
1、Java類中引用類型 的數(shù)據(jù)類型和bean的class的值一樣
2、Java類引用類型的數(shù)據(jù)類型和bean的class的值是父字關(guān)系
3、Java類引用類型的數(shù)據(jù)類型和bean的class的值是接口和實(shí)現(xiàn)類的關(guān)系
語(yǔ)法
<bean id = "myStudent" class = "Student的全路徑名稱" autowire = "byType">
基本數(shù)據(jù)類型的賦值
</bean>
<bean id = "myStudent" class = "Student的全路徑名稱" autowire = "byType">
<donstructor-arg name = "name" value = "張三"/>
<donstructor-arg name = "age" value = "20"/> name :構(gòu)造方法的形參名
// <donstructor-arg index= "3" ref= "school"/>
ref:構(gòu)造方法形參是引用類型
</bean>
<bean id = "school" class = "School的全路徑名稱" >
<property name = "name" value="清華"/>
</bean>
管理對(duì)各配置文件
多個(gè)配置文件: 一個(gè)模塊一個(gè)文件
如 學(xué)生一個(gè)
班級(jí)一個(gè)
學(xué)習(xí)一個(gè)
語(yǔ)法
再創(chuàng)建一個(gè)主配置文件
<beans>
<import resource = ClassPath:其他配置文件的路徑
</beans>
<beans>
<import resource = ClassPath:student.xml的路徑
<import resource = ClassPath:student.xml的路徑
</beans>
使用注解注入
通過(guò)注解完成對(duì)象的創(chuàng)建,代替xml
1、加入spring-context依賴
2、在類中創(chuàng)建注解
3、創(chuàng)建spring的配置文件
掃描器:指定注解在項(xiàng)目中的位置
4、使用注解創(chuàng)建對(duì)象,創(chuàng)建容器ApplicationContext
@Component(對(duì)象的名稱也就是bean的id)
此注解創(chuàng)建對(duì)象 等同 bean的功能 等同于
位置:類的上面
@Component() 默認(rèn)名稱 類名的首字母小寫 student
配置文件
配置掃描器:component - scan
base-package:注解在項(xiàng)目的包名
工作方法 :spring掃碼指定的包 找到注解 創(chuàng)建對(duì)象 賦值
三種方法
1、 <context:component-scan_base-package="包名1">
<context:component-scan_base-package="包名2">
2、<context:component-scan_base-package="包名1;包名2">
3、指定父包
<context:component-scan_base-package="父包名">
@Component("student")
public class Student(){
private String name;
private int age;
private School school; //引用數(shù)據(jù)類型
無(wú)參構(gòu)造函數(shù)
有參的構(gòu)造函數(shù)
private void setName(String name){
this.name = name;
}
private void setAge(int age){
this.age= age;
}
private void setschool(School school){
this.school= school;
}
}
其他創(chuàng)建對(duì)象的注解
這三個(gè)給項(xiàng)目分層
@Repository() 用在持久層,dao的實(shí)現(xiàn)類上面 表示創(chuàng)建對(duì)象dao能訪問(wèn)數(shù)據(jù)庫(kù)
@Service()業(yè)務(wù)層在service的實(shí)現(xiàn)類上,創(chuàng)建service對(duì)象,做業(yè)務(wù)處理,有事務(wù)等功能
@Controller() 控制層:創(chuàng)建控制器對(duì)象,接收用戶處理的參數(shù),顯示請(qǐng)求的結(jié)果
注解注入賦值
@Value(“張飛”) :簡(jiǎn)單數(shù)據(jù)類型賦值
用在String 類型上,基本數(shù)據(jù)類型不OK 可以使用包裝類
無(wú)需set方法
位置 參數(shù)上
@Value("李雙")
private String name;
@Value("20")
private int age;
//引用數(shù)據(jù)類型
引用數(shù)據(jù)類型注解注入@Autowired
:自動(dòng)注入原理 支持byName 、byType; 默認(rèn)byType
位置:在屬性的上面
屬性:required = true 賦值失敗程序報(bào)錯(cuò)
required = false 賦值失敗正常執(zhí)行、引用數(shù)據(jù)為null
@Autowired
private int age;
使用byName
在屬性上加@Autowired
@Qualifier(value = “bean的id”)表示指定名稱的bean完成賦值
@Autowired
@Qualifier("school")
private School school;
引用數(shù)據(jù)類型注解賦值@Resource
默認(rèn)byName 失敗用byType
位置參數(shù)上面
@Resource
private School school
--------------------AOP切面--------------------
動(dòng)態(tài)代理
1、實(shí)現(xiàn)方法:jdk動(dòng)態(tài)代理,使用jdk中的Proxy,Method,InvocaitonHanderl創(chuàng)建代理對(duì)象。
jdk動(dòng)態(tài)代理要求目標(biāo)類必須實(shí)現(xiàn)接口
2.動(dòng)態(tài)代理的作用:
1)在目標(biāo)類源代碼不改變的情況下,增加功能。
2)減少代碼的重復(fù)
3)解耦合。
步驟:
1、 定義一個(gè)接口
2、定義一個(gè)類ServiceTools 類中有共有的方法 (時(shí)間、事務(wù))doLog();doTrans();
2、定義一個(gè)接口的實(shí)現(xiàn)類,繼承接口 重新方法 doSome();
3、寫代理類:
繼承IncationHandler實(shí)現(xiàn)代理
public Class MyIncationHandler implement IncationHandler(){
private Object target;// 實(shí)現(xiàn)類
public MyIncationHandler(Object target){
this target = target;
}
public Object invoke(Object proxy,Method method, Object[] args)throws Throwable{
// 通過(guò)代理對(duì)象執(zhí)行方法 會(huì)調(diào)用這個(gè)invoke()
Object res = null;
ServiceTools.doLog();
// 執(zhí)行目標(biāo)類的方法,通過(guò)Method類實(shí)現(xiàn)
res = method.invoke(target,args);//執(zhí)行實(shí)現(xiàn)類的方法
ServiceTools.doTrans();
// 目標(biāo)方法的執(zhí)行結(jié)果
return res;
}
}
使用jdk實(shí)現(xiàn)代理
public class MyApp(){
public static void main(String[] args){
SomeService target = new 實(shí)現(xiàn)類;
// 創(chuàng)建InvocationHandler
InvocationHandler handler = new MyIncationHandler(target);
// 使用proxy創(chuàng)建代理
SomeService proxy = (SomeService)Proxy.newProxyInsstance{
target.getClass().getClassLoader(),
target.getClass().getInterFaces(),Handler);
// 調(diào)用handler中的invoke();
proxy.dosome();
}
}
}
aspectj實(shí)現(xiàn)AOP
步驟
1、新建maven項(xiàng)目
2、加入依賴
aspectj依賴
juint單元測(cè)試
3、創(chuàng)建目標(biāo)類:接口和實(shí)現(xiàn)類
4、創(chuàng)建切面類:普通類
(1)在類上加入@Aspect
(2) 在類中的定義方法,方法就是切面執(zhí)行的代碼(事務(wù)、日志、時(shí)間等)
在方法上加入aspectj的通知注解。如@before
有需要?jiǎng)t指定切入表達(dá)式
5、創(chuàng)建spring配置文件,聲明對(duì)象,把對(duì)象交給IOC管理
(1)聲明目標(biāo)對(duì)象
(2)聲明切面類對(duì)象
(3)聲明aspectj框架中自動(dòng)代理生成器標(biāo)簽
6創(chuàng)建測(cè)試類
接口`
public interface SomeService{
void doSome(String name,Integer age);
}
實(shí)現(xiàn)類
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name,Integer age){
Sysotem.out.println("執(zhí)行----------")
}
}
切面類
@Aspect
public class MyAspect{
方法要求
1、public
2、void
3、方法名自定義
4、方法可以有參數(shù)也可以無(wú)參數(shù)
5、@Before前置注解
1、屬性 Value 切入表達(dá)式,表示切面的執(zhí)行位置
2、位置 :在方法的上面
@Before(value = "execution(public void 包下的實(shí)現(xiàn)類.doSome(String,Integer)")
public void myBefore(){
//切面的代碼
Sysotem.out.println("時(shí)間----------")
}
}
配置文件
// 聲明目標(biāo)類(實(shí)現(xiàn)類)對(duì)象
<bean id = "someService" class = "路徑名" />
// 聲明切面類對(duì)象
<bean id = "myAspect" class = "全路徑名" />
//聲明aspectj框架中自動(dòng)代理生成器標(biāo)簽
<aop:aspectj-autoproxy>
后置通知@AfterReturn()
要求
1、public
2、void
3、方法有參數(shù) Object 方法名自定義
4、屬性 1、value:切入點(diǎn)表達(dá)式
2、returning 自定義的變量,便是目標(biāo)方法有返回值的
自定義的變量名必須和通知方法的形參一樣
位置: 方法上面
切面類 中的方法
@@AfterReturn(value = "execution(public void 包下的實(shí)現(xiàn)類.doSome(String,Integer)",returning = "res")
public void myAfterReturn(Object res){ res 和,returning = "res一樣
//切面的代碼
Sysotem.out.println("時(shí)間----------")
環(huán)繞通知@Around
屬性:value:切入表達(dá)式
位置:方法上方
特點(diǎn)
功能最強(qiáng)的通知
在目標(biāo)方法前后都能加入切面類的代碼
控制目標(biāo)方法是否調(diào)用執(zhí)行
修改原目標(biāo)方法的執(zhí)行結(jié)果,影響最后的調(diào)用結(jié)果
@Around(value = "execution(public void 包下的實(shí)現(xiàn)類.doSome(String,Integer)")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
// 實(shí)現(xiàn)環(huán)體通知
Object result = null;
Sysotem.out.println("方法前")
// 目標(biāo)方法調(diào)用
result = pjp.proceed();
Sysotem.out.println("方法后")
// 返回目標(biāo)方法的執(zhí)行結(jié)果
return result;
}
————————————————
版權(quán)聲明:本文為CSDN博主「ジ你是我永遠(yuǎn)のbugグ」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:
https://blog.csdn.net/qq_47848696/article/details/115838386
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長(zhǎng)按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
