spring學習2
使用註解配置spring
步驟:
1. 導包4(core/bean/context/spel)+1(logging)+spring-aop包(新版spring需要導入這個包)
2. 為主配置文件引入新的命名空間(約束) Context約束
3. 開啟使用註解代理配置文件
<context:component-scan base-package="com.domain"> 指定掃描 com.domain包下面所有類的註解(同時會掃描子包裏面的類)
4. 在類中使用註解完成配置
@Component("user")public class User {private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Overridepublic String toString() { return "User [name=" + name + ", age=" + age + ", car=" + car + "]"; } }
將對象註冊到容器
@Component(“user”)
@Service(“user”) service層
@Controller(“user”) web層
@Repository(“user”) dao層
本質上這四個功能都是一樣 只是為了見名知意
修改對象的作用範圍
@Scope(scopeName=”prototype”) 指定對象的作用範圍 同樣也是作用在實體上面
值類型註入
@Value("tom")
private String name;
通過反射來為Field賦值 ,但是這樣破壞了封裝性
通過set方法來賦值 推薦使用
@Value("24") public void setAge(Integer age) { this.age = age; }
引用類型註入
1.使用AutoWired 自動裝配
@Component("user") public class User { @Autowired private Car car; setCar/getCar ... } @Component class Car{ private String cName; private String color;
get/set ... } 註意:使用自動裝配,被裝配的字段 也要在容器有 可以沒有名字
這種方式有一個壞處:如果匹配多個類型一致的對象,將無法選擇具體註入哪一個對象
解決辦法:使用 Qualifier("car") 通過該註解來告訴 spring容器自動裝配哪個名稱的對象
註意:Qualifier和AutoWired要一起使用
@Resource(name="car") 手動註入,指定註入哪個名稱的對象
@Resource(name="car") private Car car;
初始化 | 銷毀方法
@PostConstruct // 在對象被創建以後調用 相當於配置文件中定義的init-method public void init() { System.out.println("init method"); } @PreDestroy // 在對象被銷毀前調用 destory-method public void destory(){ System.out.println("destory method"); }
spring與junit整合測試
1.導包 4+2+aop+test
2.配置註解
@RunWith(SpringJUnit4ClassRunner.class) // 幫我們創建容器 @ContextConfiguration("classpath:applicationContext.xml") //指定創建容器時使用的配置文件 public class Student { @Value("wanglei") private String name; @Test public void test() { System.out.println(name); } @Value("24") private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
spring中的aop
aop思想介紹 橫向重復代碼 ,縱向抽取
例如:解決亂碼問題 管理事務 action攔截器
spring中的aop概念 ------> spring能夠為容器中管理的對象生成動態代理對象
以前我們要使用動態代理,需要自己調用下面的方法
Proxy.newProxyInstance(xx,xx,xx) 生成代理對象
現在spring能夠幫助我們生成代理對象
spring實現aop的原理
1.動態代理(優先) : 被代理對象必須要實現接口,才能產生代理對象,如果沒有接口將不能使用動態代理技術。
2.cglib代理(沒有接口) : 第三方代理技術,cglib代理可以對任何類生成代理,代理的原理是對目標對象進行繼承代理.
但是如果目標對象被final修飾,那麽該類無法被cglib代理.
步驟:
1.創建service的接口是實現類
public interface UserService { void save(); void add(); void delete(); void find(); } public class UserServiceIml implements UserService { public void save() { System.out.println("save"); } public void add() { System.out.println("add"); } public void delete() { System.out.println("delete"); } public void find() { System.out.println("find"); } }
2.使用cglib代理生成代理對象
public class Test implements MethodInterceptor{ public UserService getService() { Enhancer en=new Enhancer(); //用於生成代理對象 en.setSuperclass(UserServiceIml.class);//對誰設置代理 en.setCallback(this); //代理要做什麽 UserService service = (UserService) en.create();//創建代理對象 return service; } @Override proxyObj 目標類的實例 method 目標類方法的反射實例 arg 參數 methodProxy 代理類實例 public Object intercept(Object proxyObj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable { System.out.println("打開事務!"); Object returnValue = methodProxy.invokeSuper(proxyObj, arg); System.out.println("提交事務!"); return returnValue; } }
3.測試
public static void main(String[] args) { Test test = new Test(); UserService service = test.getService(); service.save(); }
AOP名詞學習
Joinpoint(連接點):目標對象中,所有可以增強的方法
Pointcut(切入點): 目標對象,已經增強的方法
Advice(通知/增強):增強的代碼
Target(目標對象): 被代理的對象
Weaving(織入):將通知應用到切入點的過程
Proxy(代理):將通知織入到目標對象之後,形成代理對象
Aspect(切面):切入點 + 通知
spring中的aop演示
步驟:
1.導包4(core + bean + spel + context)+2 + 2(aop + aspect) + 2(allowiance + weaving)
aop包 + aspect包 + aopalliance + weaver
2.準備目標對象
3.準備通知
前置通知 目標方法運行之前調用
後置通知(如果出現異常不會調用) 在目標方法運行之後調用
環繞通知 在目標方法之前和之後都調用
異常攔截通知:如果出現異常,就會調用
後置通知(無論是否出現異常都會調用) :在目標方法運行之後調用
public class MyAdvice { //前置通知 public void before() { System.out.println("前置通知"); } //後置通知 public void afterReturn() { System.out.println("後置通知(如果出現異常不會被調用)"); } //環繞通知 public Object around(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("這是環繞通知之前的部分"); Object proceed = pjp.proceed();//調用目標方法 System.out.println("這是環繞通知之後的部分"); return proceed; } //異常攔截通知 public void afterException() { System.out.println("出現異常了"); } //後置通知 public void after() { System.out.println("後置通知(出現異常也會調用)"); } }
4.配置進行織入,將通知織入目標對象中
準備工作:導入AOP(約束)命名空間
1.配置目標對象 將具體的實現類(而不是接口添加進來) 因為是為 實現類來創建代理對象
<bean name="userService" class="..."></bean>
2.配置通知對象
<bean name="myAdvice" class="...">
3.配置切入點
<aop:pointcut expression="execution(* cn.itcast.service.*ServiceImpl.*(..))" id="pc"/>
execution有以下幾種形式
public void cn.itcast.service.UserServiceImpl.save() 具體的某個方法
void cn.itcast.service.UserServiceImpl.save()
* cn.itcast.service.UserServiceImpl.save() 任意返回值
* cn.itcast.service.UserServiceImpl.*() 任意方法名/任意返回值
* cn.itcast.service.*ServiceImpl.*(..) 任意參數/ 任意返回值/ 任意方法名
* cn.itcast.service..*ServiceImpl.*(..) 還會找這個下面的子包
<aop:config> <aop:pointcut expression="execution(* com.domin.*Service.*(..))" id="pc"/> <aop:aspect ref="advice"> <aop:before method="before" pointcut-ref="pc"/> <aop:around method="around" pointcut-ref="pc"/> <aop:after-throwing method="afterException" pointcut-ref="pc"/> <aop:after method="after" pointcut-ref="pc"/> <aop:after-returning method="afterReturn" pointcut-ref="pc"/> </aop:aspect> </aop:config>
調用順序
1.沒有發生異常的情況下
前置通知
這是環繞通知之前的部分
save method
這是環繞通知之後的部分
後置通知(出現異常也會調用)
後置通知(如果出現異常不會被調用)
2.發生異常的情況下
前置通知
這是環繞通知之前的部分
出現異常了
後置通知(出現異常也會調用)
註解配置實現動態代理
1.導包
2.配置
同樣需要加入 <bean name="userService" class="..."></bean> 和 <bean name="myAdvice" class="...">
3.使用註解來實現代理
4.在配置文件中加入 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 表示開啟使用註解完成織入
5.測試
spring學習2